2009-07-31 16 views
2

Diese Frage von Joels inspiriert „Making Falscher Code Falscher Look“Können wir das Typsystem nutzen, um Programme sicherer zu machen?

http://www.joelonsoftware.com/articles/Wrong.html

Manchmal Sie Typen verwenden können Semantik auf Objekte über ihre Schnittstellen zu erzwingen. Zum Beispiel definiert die Java-Schnittstelle Serializable nicht wirklich Methoden, aber die Tatsache, dass ein Objekt Serializable implementiert, sagt etwas darüber aus, wie es verwendet werden soll.

Können wir UnsafeString und SafeString Schnittstellen/Subklassen in, sagen wir, Java, die auf die gleiche Weise wie Joels Ungarische Notation und Javas Serializable verwendet werden, so dass es nicht nur schlecht aussieht - es kompiliert nicht ?

Ist das in Java/C/C++ machbar oder sind die Typsysteme zu schwach oder zu dynamisch?

Welche anderen Sicherheitsfunktionen können auf diese Weise über die Eingabebereinigung hinaus implementiert werden?

+1

Dies wird auch in Podcast 58 (http://blog.stackoverflow.com/2009/06/podcast-58/) beschrieben – Brian

+0

es ist im Grunde, was ein Typ System * ist *. Ohne das Typsystem könnte jede Variable wie jede andere behandelt werden. Sie könnten auf den Speicher außerhalb der Grenzen zugreifen, indem Sie z. B. einen Int als Doppel behandeln. Das würde Sie den Wert der 4 Bytes nach dem Ende des int erhalten. Oder vorzeichenlose Ganzzahlen verhindern, dass Sie signierte Werte versehentlich speichern. (Obwohl die Art, wie sie es still konvertieren, nicht ideal ist) – jalf

+0

Richtig, aber es scheint, als ob es eine höhere Ebene von Eigenschaften gibt, die wir im Typsystem erzwingen können, die wenig damit zu tun hat, wie wir die Datendarstellung manipulieren.Ich denke, dass ich das Typsystem weiter in die Geschäftslogik einbinden werde. –

Antwort

3

Das Typensystem bereits erzwingt eine Vielzahl solcher Sicherheitsfunktionen. Das ist im Wesentlichen, was es für ist.

Für ein sehr einfaches Beispiel verhindert es, dass Sie einen Float als int behandeln. Das ist ein Aspekt der Sicherheit - es garantiert, dass sich der Typ, an dem Sie arbeiten, wie erwartet verhält. Es garantiert, dass nur String-Methoden für eine Zeichenfolge aufgerufen werden. Die Montage verfügt beispielsweise nicht über diese Schutzfunktion.

Es ist auch die Aufgabe des Typsystems, sicherzustellen, dass Sie keine privaten Funktionen einer Klasse aufrufen. Das ist ein weiteres Sicherheitsmerkmal.

Javas Typensystem ist zu schwach, um viele interessante Einschränkungen wirksam durchzusetzen, aber in vielen anderen Sprachen (einschließlich C++) kann das Typsystem verwendet werden, um weit umfangreichere Regeln zu erzwingen.

In C++ bietet die Metaprogrammierung von Vorlagen viele Tools zum Verhindern von "schlechtem" Code. Beispiel:

class myclass : boost::noncopyable { 
... 
}; 

erzwingt zur Kompilierzeit, dass die Klasse nicht kopiert werden kann. Im Folgenden wird produzieren Fehler kompilieren:

myclass m; 
myclass m2(m); // copy construction isn't allowed 
myclass m3; 
m3 = m; // assignment also not allowed 

Ebenso wir zur Compile-Zeit sicherstellen kann, dass eine Template-Funktion wird nur auf Typen genannt, die bestimmte Kriterien erfüllen (sagen wir, sie Random-Access-Iteratoren sein muss, während bilinear diejenigen sind nicht erlaubt, oder sie müssen POD-Typen sein, oder sie dürfen keine Integer-Typen sein (char, short, int, long), aber alle anderen Typen sollten legal sein

Ein Lehrbuchbeispiel für Template-Metaprogrammierung in C++ implementiert eine Bibliothek zum Berechnen von physikalischen Einheiten.Es ermöglicht Ihnen, einen Wert vom Typ "Meter" mit einem anderen Wert des gleichen Typs zu multiplizieren und automatisch bestimmt, dass das Ergebnis vom Typ "Quadratmeter" sein muss Geben Sie als Typ "Meile" einen Wert vom Typ "Stunde" ein und erhalten Sie eine Einheit vom Typ "Meilen pro Stunde".

Noch einmal, eine Sicherheitsfunktion, die verhindert, dass Sie Ihre Typen durcheinander bringen und versehentlich Ihre Einheiten durcheinander bringen. Sie erhalten einen Kompilierungsfehler, wenn Sie einen Wert berechnen und versuchen, ihn dem falschen Typ zuzuordnen. Versuchen Sie, z. B. Liter durch meters^2 zu teilen und das Ergebnis einem Wert von beispielsweise Kilogramm zuzuweisen, wird zu einem Kompilierungsfehler führen.

Das meiste davon erfordert einige manuelle Arbeit, aber die Sprache gibt Ihnen die Werkzeuge, die Sie brauchen, um die gewünschten Typ-Checks zu erstellen. Einige davon könnten besser direkt in der Sprache unterstützt werden, aber die kreativeren Prüfungen müssten in jedem Fall manuell implementiert werden.

+0

+1 für Kommentar re physikalische Einheiten. Ich würde jedem Programmierer empfehlen, die dort beteiligten Konzepte zu sehen. Es zeigt wirklich die Kraft und Flexibilität, die C++ gegenüber jeder anderen Sprache hat. (http://learningcppisfun.blogspot.com/2007/01/units-and-dimensions-with-c-templates.html). –

+0

Nicht "andere". Wie in einigen der anderen Antworten erwähnt, wäre vieles davon in Ada trivial gewesen, zum Beispiel – jalf

-1

Sie können keine UnsafeString-Unterklasse von String in Java seit java.lang.String is final haben.

Im Allgemeinen können Sie auf der Quellenebene keine Sicherheit bieten - wenn Sie vor bösem Code schützen möchten, müssen Sie dies auf der binären Ebene (z. B. Java-Bytecode) tun. Deshalb kann private/protected nicht als Sicherheitsmechanismus in C++ verwendet werden: Es ist möglich, das mit Zeigermanipulationen zu umgehen.

+0

Wir schützen nicht vor bösartigem Java-Code. Wir schützen vor bösartigen Eingaben (zum Beispiel für Cross-Site-Scripting). Es ist der Wunsch, den Compiler anstelle von Joels ungarischer Methode für "Gerüche" zu verwenden. –

+0

Aber guten Ruf auf den letzten Unterrichtsteil. Dies wäre jedoch eher eine Hürde als eine Sackgasse. –

1

Ja, Sie können so etwas tun. Ich weiß nichts über Java, aber in C++ ist es nicht üblich und es gibt keine Unterstützung dafür, also müssen Sie etwas manuelle Arbeit machen. Es ist üblich in einigen anderen Sprachen, zum Beispiel Ada, die das Äquivalent eines typedef haben, der einen neuen Typ einführt, der nicht implizit in das ursprüngliche konvertiert werden kann (dieser neue Typ "erbt" einige grundlegende Operationen von dem einen) erstellt, damit es nützlich bleibt).

BTW, im Allgemeinen Vererbung ist kein guter Weg, um die neuen Typen einzuführen, als auch wenn es keine implizite Umwandlung auf die eine Weise gibt, gibt es eine in der anderen.

+2

Was meinst du damit, ist es in C++ nicht üblich? Eine große Anzahl von Metaprogrammierungstricks soll genau diese Art von Sicherheit erreichen. Die meisten von boost :: type_traits, sowie statische Assert, nicht kopierbare und eine große Anzahl anderer Dienstprogramme sind dafür ausgelegt. – jalf

+1

Einverstanden. Solange es Ihre Aufgabe ist, es zu erschweren, zu vergessen, die Daten vor der Speicherung, Manipulation oder Anzeige zu bereinigen, ist eine "unsichere" Art, die nicht in den "sicheren" Typ umgewandelt werden kann, eine vernünftige Lösung. – wowest

+0

Klingt, als ob du seinen Punkt auf mich zurücksicherst, jalf, –

0

Sie können eine bestimmte Menge davon in Ada out of the box tun. Sie können z. B. Integertypen erstellen, die nicht miteinander kompatibel sein können, und Ada-Enumerationen sind nicht mit einem Integer-Typ kompatibel. Sie können immer noch zwischen ihnen konvertieren, aber Sie müssen explizit tun, was Aufmerksamkeit auf was Sie tun.

Sie könnten das gleiche mit dem heutigen C++ tun, aber Sie müssten alle Integer und Enums in Klassen umbrechen, was einfach zu viel Arbeit für etwas ist, das einfach sein sollte (oder noch besser, der Standard) Art Dinge zu tun).

Ich verstehe die nächste Version von C++ wird zumindest das Aufzählungsproblem beheben.

0

In C++ könnten Sie vermutlich typedef verwenden, um ein Synonym für einen primitiven Typ zu erstellen. Ihr Synonym könnte etwas über den Inhalt dieser Variable implizieren, wobei die Funktion der ungarischen Notation der Apps ersetzt wird.

Intellisense meldet das Synonym, das Sie bei der Deklaration verwendet haben. Wenn Sie also ungarisch nicht verwenden möchten, können Sie damit nicht scrollen (oder Go to Definition verwenden).

+0

Ich habe das mit ganzen Zahlen gemacht, die physikalische und logische Seiten- und Blocknummern auf einem Flash-Dateisystem darstellen. Die Typen unterstützten Standardumwandlungen von und in Integer, aber nicht voneinander und voneinander. Hat geholfen, ein paar Probleme zu fangen (im Allgemeinen habe ich die benutzerdefinierten Typen verwendet, aber für einige Schleifen und solche ganzen Zahlen waren notwendig). Der eigentliche Build verwendete Ganzzahlen, aber Emulation/Test-Builds verwendeten die benutzerdefinierten Typen. Da die Verwendung verschiedener Typen die Kompilierungszeit für die Typsicherheit gewährleistete, sollte die Tatsache, dass der Emulations-/Test-Build sauber war, dazu führen, dass der echte Build, der Ganzzahlen verwendet, sauber sein sollte. – supercat

0

Ich denke, Sie denken an etwas in Anlehnung an Perls "Tainting" -Analyse.

In Java sollte es möglich sein, benutzerdefinierte Anmerkungen und einen Annotationsprozessor zu verwenden, um dies zu implementieren. Nicht unbedingt einfach.

Verwandte Themen