Geschwindigkeit vs. Sicherheit
-
Optimizer schrieb:
Das geht über den Speicherschutz der Hardware.
Aber auch nur, wenn auf der entsprechenden Hardware einer vorhanden ist, gelle?
Optimizer schrieb:
Tatsächlich findet sie sowieso "in beiden Sprachen" immer statt
Ich kann nur von C++ sprechen, und da ist "immer" übertrieben. Man macht es eigentlich nur, wenn Zeiger über Schnittstellen geschickt werden (und entsprechend dokumentiert sind), oder ein Zeiger erstmal default auf Null gesetzt wird und später eine gültige Adresse zugewiesen bekommt. Was man allerdings möglichst vermeiden sollte, und schön RAII verwenden sollte. Ansonsten hat man immer einen gültigen Zeiger (nicht initialisierte jetzt mal aussen vor gelassen).
-
Optimizer schrieb:
Null-Exceptions sind Dinge, die sich komplett zur Compile-Zeit eliminieren lassen würden
class Foo { private Bar bar; function Foo() { bar=null; //do a lazy initialize } private void ensure_is_initialized() { if(!is_initialized()) initialize(); } private boolean is_initialized() { return bar!=null; } private initialize() { bar = new Bar();//expesnive initialization code } public void do_smth_good() { ensure_is_initialized(); bar.do_smth_good(); } public void do_smth_bad() { bar.do_smth_bad(); } }
wie checkst du das zur compile time?
-
groovemaster schrieb:
...
Erstmal, ich dachte eigentlich, dass es in Java keine Zeiger gibt, aber egal....Es gibt eigentlich in Java NUR Pointer. Es gibt zwar keine void*, aber ansonsten erfüllt das, was in Java "Referenz" genannt wird, alle Kriterien von dem, was in C++ "Pointer" genannt wird. Was es dagegen nicht gibt, sind "Stackobjekte" und "Referenzen (wie es sie in C++ gibt)".
Deswegen finde ich ja dieses "Java ist sicher, weil es keine Pointer gibt" so lächerlich und falsch. Probleme mit Pointern gibt es eigentlich nur da, wo sie woanders hinzeigen als man meint/will. Das kann man in Java ebenso leicht machen wie in C++....
Aber "echte Zugriffssicherheit", wie sie Dir ein Stackobjekt oder (in Grenzen) eine C++-Referenz bietet, gibt's in Java gar nicht...Insgesamt teile ich Deine Erfahrung: Leute, die Java für die "sichere" Sprache halten, haben oft aufgrund falscher Beratung/Einarbeitung/Beispiele/... schlechte Erfahrung mit C++ gemacht (meistens in Sachen Stringbearbeitung) und meinen, wenn sie schlechte Programme geschrieben haben, wäre das das Problem der Sprache.
Wenn man mal ins C++-Unterforum schaut, stellt man mit Erschrecken fest, dass fast alle C++-Anfänger mit char[]-und anderem Array-Zeugs anfangen und immer erst mühsam auf std::string und std::vector hingewiesen werden müssen !
Ich frage mich, wer die ganzen Kollegen so konsequent auf die falsche Fährte schickt (vermutlich alte "C-Hasen", die sich jede noch so kleine Hilfsfunktion immer wieder neu selbst schreiben).....Natürlich bietet einem Java mit seiner VM und seinen eingeschränkten Möglichkeiten eine niedrige Einstiegsschwelle ... man kommt schnell zu einem Hello-World, bekommt einen einfachen und konsistenten Einblick in OO-Programmierung, ....
Aber die "Fehler findet man eben zur Laufzeit"-Philosophie frisst IMO die Nerven dafür später (und bei größeren Programmen) und über bestimmte Programmierformen/-bereiche lernt man in Java nie wieder etwas (generische Programmierung, Compiletime-Polymorphie, Performanceoptimierung, Speicherverwaltung, ....).Damit ist für mich Java tatsächlich eine gute (wenn nicht gar ideale) Sprache da, wo man viel mit Ein-/Umsteigern , stark nichttechnischen Anforderungen, GUIs, .... zu tun (z.B. in unserer Firma) und eine Anforderung an niedrige Codingzeiten (die dann allerdings im Test und Produktivsetzung/-betrieb wieder verbraten werden) hat.
Wer "Lust auf mehr" (Technik(en)) hat, ist mit IMO C++ besser bedient.
Gruß,
Simon2.
-
Ich glaub ja eh, die am Besten durchdachte Sprache ist Ada. Die hat ihre Stärken wirklich im Sicherheitsbereich. Wird nicht umsonst in der Luft - und Raumfahrtbranche eingesetzt.
-
GPC schrieb:
Ich glaub ja eh, die am Besten durchdachte Sprache ist Ada. Die hat ihre Stärken wirklich im Sicherheitsbereich. Wird nicht umsonst in der Luft - und Raumfahrtbranche eingesetzt.
Klingt interessant. Muß ich mir mal anschauen...
Danke,
Simon2.
-
Was z.B. ein sehr witziges Feature ist: Ich kann einer Variablen sagen, welchen Wertebereich sie haben darf (nein, nicht über den Typ
). So kann ich bei einer Integer-Variable sagen, sie darf Werte zw. -5 und 5 annehmen. Alles andere löst einen Sicherheitsfehler aus.
Automatische Index-Checks sowie Checks auf Speicher-Zugriffsfehler sind natürlich auch dabei. Kann auch alles deaktiviert werden.Außerdem eignet sich die Sprache sehr gut für die automatische Verifikation von Programmen.
Ja, ich glaube Ada ist wirklich sehr gut durchdacht, nur die Syntax is etwas schräg, aber immer noch besser als bei LISP
-
GPC schrieb:
Was z.B. ein sehr witziges Feature ist: Ich kann einer Variablen sagen, welchen Wertebereich sie haben darf (nein, nicht über den Typ
). So kann ich bei einer Integer-Variable sagen, sie darf Werte zw. -5 und 5 annehmen. Alles andere löst einen Sicherheitsfehler aus.
Und was ist daran "besser" als an einer Realisierung durch nen eigenen Typ?
-
byto schrieb:
GPC schrieb:
Was z.B. ein sehr witziges Feature ist: Ich kann einer Variablen sagen, welchen Wertebereich sie haben darf (nein, nicht über den Typ
). So kann ich bei einer Integer-Variable sagen, sie darf Werte zw. -5 und 5 annehmen. Alles andere löst einen Sicherheitsfehler aus.
Und was ist daran "besser" als an einer Realisierung durch nen eigenen Typ?
Na ja, es ist halt sauber und einfach in die Sprache integriert und daher ohne viel Aufwand zu realisieren. Wenn ich z.B. in C++ den Wertebereich (sagen wir grad mal -5 und 5) einschränken will, ist das schon aufwändiger.
-
Also ein...
type WINKEL is delta 0.01 range 0.0..360.0;
hat schon was
-
Shade Of Mine schrieb:
wie checkst du das zur compile time?
Die Behauptung war nicht, zur compile-Zeit auf null prüfen zu können. Aber man kann immer verhindern, dass irgendwo unerwartet null steht. Dazu musst es zwei Zeigertypen geben, einen Foo und einen Foo? und nur der Foo? darf null sein. Foo kann immer implizit in ein Foo? umgewandelt werden, aber umgekehrt muss "gecasted" werden.
Der Compiler könnte bei so einem Cast einen auch zwingen, Code für den Fall zu schreiben, dass der Pointer null ist (ähnlich wie checked Exceptions). Das wäre supergeil.
-
groovemaster schrieb:
Optimizer schrieb:
Das geht über den Speicherschutz der Hardware.
Aber auch nur, wenn auf der entsprechenden Hardware einer vorhanden ist, gelle?
Wenn keiner vorhanden ist, dann muss der Test explizit vom JIT-compiler eingebaut werden. Aber gerade ohne Speicherschutz sind noch strengere Tests durchaus zu befürworten. Ohne Speicherschutz und ohne Garantien wie sie beispielsweise Java bietet, könntest du kein sicheres Betriebssystem schreiben.
Optimizer schrieb:
Tatsächlich findet sie sowieso "in beiden Sprachen" immer statt
Ich kann nur von C++ sprechen, und da ist "immer" übertrieben. Man macht es eigentlich nur, wenn Zeiger über Schnittstellen geschickt werden (und entsprechend dokumentiert sind), oder ein Zeiger erstmal default auf Null gesetzt wird und später eine gültige Adresse zugewiesen bekommt. Was man allerdings möglichst vermeiden sollte, und schön RAII verwenden sollte. Ansonsten hat man immer einen gültigen Zeiger (nicht initialisierte jetzt mal aussen vor gelassen).
Du verstehst nicht ganz, worauf ich hinauswollte: Weder du noch der Compiler bauen Prüfungen beim Speicherzugriff ein. Das macht die MMU des Prozessors und das Betriebssystem hat als einziges Programm das Recht, den Schutz abzustellen. Dass du einen 0-Pointer nicht dereferenzieren kannst liegt daran, weil bei 0 das Textsegment steht und das Betriebssystem dem Prozessor sagt "nur innerhalb dieser Segmente darfste das und das". Den Test hast du immer und kannst dich nicht dagegen wehren.
Schlägt jetzt so eine Prüfung fehl, wird der entsprechende Interrupt-Handler vom BS abgearbeitet. Das kann benutzt werden, um in C++ Programmen eine access violation anzuzeigen (anstatt den Prozess gleich zu beenden) - oder in Java eine NullPointerException. Das kostet "nichts", weil du es sowieso immer bezahlst. Ausnahmen sind die seltenen Fälle wo der Speicherschutz nicht so schnell greifen würde wie eine explizite Prüfung auf null.
-
Optimizer schrieb:
Du verstehst nicht ganz, worauf ich hinauswollte: Weder du noch der Compiler bauen Prüfungen beim Speicherzugriff ein. Das macht die MMU des Prozessors und das Betriebssystem hat als einziges Programm das Recht, den Schutz abzustellen.
Ja, das interessiert dich als Hochsprachenprogrammierer aber überhaupt nicht. Java garantiert dir eine entsprechende Exception, deshalb müssen auch die Voraussetzungen dafür geschaffen werden. Darum schrieb ich, dass dort generell ein Overhead da ist, egal ob sich das nun tatsächlich +performacetechnisch niederschlägt oder nicht, weil die CPU zB einen hardwareseitigen Schutz hat. In C++ gibt es diese Restriktionen eben nicht. Da hast du minimal keinen Overhead, weder soft- noch hardwareseitig. Weil deine CPU dies zB nicht unterstützt, und auch softwareseitig keine Prüfung notwendig ist (zB weil du dich auf das Ergebnis von new verlassen kannst). Bis maximal 2mal Overhaed, soft- und hardwareseitig. Allerdings kann man dort, natürlich leider nur plattformabhängig, die Funktionalität des Betriebssystems ausnutzen, so dass keine explizite Prüfung mehr notwendig ist.
-
In C++ gibt es diese Restriktionen eben nicht. Da hast du minimal keinen Overhead, weder soft- noch hardwareseitig.
Das mag für das Programmieren von Mikro-Controllern noch stimmen, auf einem typischen Desktop-System aber brauchst du ohne Wenn und Aber ein sicheres Betriebssystem. Und genau wenn man so weit schon ist, dass man ein sicheres Betriebssystem braucht, kann der Ansatz von C++ sich zum Performance-Nachteil entwickeln.
ftp://ftp.research.microsoft.com/pub/tr/TR-2006-43.pdf schrieb:
These mechanisms can incur non-trivial performance costs. Mapping
from virtual to physical addresses can incur overheads up to 10–
30% due to exception handling, inline TLB lookup, TLB reloads,
and maintenance of kernel data structures such as page tables
[28]. In addition, virtual memory and privilege levels increase the
cost of inter-process communication.Umgekehrt können Garantien die dir Sprachen wie Java bieten, ausgenutzt werden, um eine höhere Performance zu erreichen. Der Punkt dabei ist, dass man auf Grund dieser Garantien auf ein Stück Überwachung verzichten kann. Ein sehr interessantes Forschungsprojekt dazu ist IMHO Singularity, ein Betriebssystem von Microsoft, welches auf den Hardware-seitigen Schutz der Prozesse gegeneinander verzichtet. Das ermöglicht eine deutlich schnellere Interprozess-Kommunikation und performante Mikrokernel-Architektur (d.h. auch Treiber laufen in eigenen abgeschotteten Prozessen, was die Sicherheit weiter erhöht).
Das Betriebssystem soll aber keineswegs ohne Schutz sein. Microsoft nennt das, was man heute durch Speichersegmentierung und Schutz durch die MMU erreicht "Hardware isolated processes" und stellt dem "Software isolated processes" gegenüber, die die Eigenschaften von "sicheren" Programmiersprachen ausnutzen um nur Speicherzugriffe zu überwachen, auf die es ankommt. Ausführbare Programme liegen in .Net-Code vor und laufen praktisch ohne Speicherschutz ab.
-
Optimizer schrieb:
Umgekehrt können Garantien die dir Sprachen wie Java bieten, ausgenutzt werden, um eine höhere Performance zu erreichen. Der Punkt dabei ist, dass man auf Grund dieser Garantien auf ein Stück Überwachung verzichten kann. Ein sehr interessantes Forschungsprojekt dazu ist IMHO Singularity, ein Betriebssystem von Microsoft, welches auf den Hardware-seitigen Schutz der Prozesse gegeneinander verzichtet. Das ermöglicht eine deutlich schnellere Interprozess-Kommunikation und performante Mikrokernel-Architektur (d.h. auch Treiber laufen in eigenen abgeschotteten Prozessen, was die Sicherheit weiter erhöht).
Singularity ist doch genau das Gegenteil einer µKernel-Architektur. Anstelle nur wenig Code im kritischen Bereich (Ring0) einzusetzen, packen die da nicht nur eine komplette VM rein, sondern auch alle Treiber und Programme die ausgeführt werden. Das der "mehr Code" -> "mehr Sicherheits"-Ansatz fundamentale Fehler hat, sieht man ja allein an den Sicherheitslücken, der Java VMs.
Der µKernel hat ja das Prinzip möglichst wenig Code in Ring0 platzieren, so das man den Code leicht prüfen kann.
-
Singularity ist genau die µKernel-Architektur. Du darfst dich nicht dadurch täuschen lassen, dass der Hardwareschutz für alle Prozesse ausgeschaltet ist, die Prozesse können auf Grund der genannten Garantien ihren Speicherbereich trotzdem nicht verlassen. Der Schutz ist genauso vollkommen wie man es sich nur wünschen kann. In Singularity laufen auch Treiber als eigene Prozesse und man kann mit ihnen nur über die Interprozess-Kommunikation kommunizieren (was dort aber sehr schnell ist). Das ist µKernel par excellence.