c++ vs. java... was hat zukunft



  • pale dog schrieb:

    CStoll schrieb:

    Schutz gegen Vorsatz (und Sachen wie reinterpret_cast<> sind Vorsatz) kann wohl keine Sprache geben....

    doch, Java :p

    OK, in Java kann man mir schlechter vorsätzlich das Design kaputtmachen (obwohl - ein Cast von Point nach MutablePoint funktioniert und hat den selben Effekt wie ein const_cast<> in C++ Code). Aber dafür ist es umso leichter, fahrlässig das Programm zu zerlegen (und erfordert Aufwand, halbwegs const-korrekte Programme zu bauen).

    CStoll schrieb:

    PS: Und afair sind alle Klassen in Java miteinander verwandt - und wenn nur über ihren Urahnen Object.

    man kann ein object zwar nach 'Object' casten, aber dann auch nur die methoden aufrufen, die 'Object' anbietet, und die sind echt harmlos.
    --> http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html
    ein cast:

    Apfel a = (Apfel)eineBirne;
    

    ist nicht möglich.
    🙂

    Was heißt "nicht möglich"? Wird das schon vom Compiler geblockt oder erst zur Laufzeit?



  • templäd schrieb:

    Nur setzt der Schutz auch merklich spät an. Wenn ich ein Objekt in einen inkompatiblen Typ casten will dann flieg ich zur Laufzeit auf die Schnauze.
    Zumindest mit einer akzeptablen Fehlermeldung

    das dürfte nicht abstürzen und trotzdem seinen zweck erfüllen:

    // echt liebe klasse, von echt coolem C++ designer
    class A
    {
        private: const int a,b,c; // const und private, da kommt keiner dran  
    };
    
    // harharhar, aber ich schon !!!
    class Intruder
    {
        public: int a,b,c;
    };
    
    // mit 'const' nur so zugenagelt
    void liebe_funktion (const A*const  a)
    {
      // böser programmierer fügt code ein...
      Intruder *b = (Intruder*)a;  // hähäh !!!
      // C++ sucks, Sorry, but it does !!!
      b->a = b->b = b->c = 0x1234;  // hihihih !!!
    }
    

    CStoll schrieb:

    man kann ein object zwar nach 'Object' casten, aber dann auch nur die methoden aufrufen, die 'Object' anbietet, und die sind echt harmlos.
    --> http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html
    ein cast:

    Apfel a = (Apfel)eineBirne;
    

    ist nicht möglich.
    🙂

    Was heißt "nicht möglich"? Wird das schon vom Compiler geblockt oder erst zur Laufzeit?

    es lässt sich nicht compilieren.
    🙂



  • Ja, wer böswillig sein will, geht sicher auch noch den Schritt weiter und schreibt Apfel a = (Apfel)(Object)eineBirne; (und wenn mich meine Erinnerung nicht täuscht, sollten beide Casts problemlos vom Compiler geschluckt werden). Und selbst wenn es keine Entsprechung zu reinterpret_cast<> in Java gibt, bleiben immer noch Angriffsmöglichkeiten für einen böswilligen Programmierer - aber die sind auch nicht das Thema (Stichwort: Vorsatz vs. Fahrlässigkeit).



  • Es lässt sich nicht compilieren, weil Apfel und Birne nicht in der selben Hirarchie sind. Richtig. ABER, das was wohl eher auf Java-Code zutrifft, ist ja wohl eher das, das man von Object auf einen konkreten Typ castet. Oder von einem Interface auf einen konkreten Typen. Sagen wir mal, ich habe Interface ILogIn und dazu mehrere Implementierungen. Und ich habe sowas:

    ILogIn getLogin();
    
    MyLogIn log = (MyLogIn) getLogin();
    

    Dann werde ich mit einem ClassCastException rechnen müssen.
    Noch schlimmer ist es aber, wenn sowas existiert (was in Java usos ist):

    Object get();
    

    Horror! Was haben wir hier in unseren Produktiven Systemen schon alles an ClassCastExceptions gesehen...



  • CStoll schrieb:

    Ja, wer böswillig sein will, geht sicher auch noch den Schritt weiter und schreibt Apfel a = (Apfel)(Object)eineBirne; (und wenn mich meine Erinnerung nicht täuscht, sollten beide Casts problemlos vom Compiler geschluckt werden). Und selbst wenn es keine Entsprechung zu reinterpret_cast<> in Java gibt, bleiben immer noch Angriffsmöglichkeiten für einen böswilligen Programmierer - aber die sind auch nicht das Thema (Stichwort: Vorsatz vs. Fahrlässigkeit).

    👍 😮 habs gerade in Eclipse ausprobiert, der Compiler schluckt es!



  • pale dog schrieb:

    // echt liebe klasse, von echt coolem C++ designer
    class A
    {
        private: const int a,b,c; // const und private, da kommt keiner dran  
    };
    
    // harharhar, aber ich schon !!!
    class Intruder
    {
        public: int a,b,c;
    };
    
    // mit 'const' nur so zugenagelt
    void liebe_funktion (const A*const  a)
    {
      // böser programmierer fügt code ein...
      Intruder *b = (Intruder*)a;  // hähäh !!!
      // C++ sucks, Sorry, but it does !!!
      b->a = b->b = b->c = 0x1234;  // hihihih !!!
    }
    

    💡 Das geht auch einfacher ( ⚠ aber nie so benutzen ⚠ und wenn doch, dann nicht verraten, daß ich es gesagt habe):

    #define private public
    #include <einfremderheader.h>
    

    C++ lässt halt vieles zu, aber vieles muß, bzw. kann ich explizit machen. Es gibt manchmal Spezialfälle, wo ich mich über gewisse Schutzmechanismen hinweg setzten möchte. Und das geht mit C++. Sicher macht das die Sprache nicht sicherer, aber ich werde von der Sprache auch nicht in den Möglichkeiten eingeschränkt. Mit C++ lässt sich einfach (fast) alles machen, was der Rechner her gibt.



  • Artchi schrieb:

    CStoll schrieb:

    Ja, wer böswillig sein will, geht sicher auch noch den Schritt weiter und schreibt Apfel a = (Apfel)(Object)eineBirne; (und wenn mich meine Erinnerung nicht täuscht, sollten beide Casts problemlos vom Compiler geschluckt werden). Und selbst wenn es keine Entsprechung zu reinterpret_cast<> in Java gibt, bleiben immer noch Angriffsmöglichkeiten für einen böswilligen Programmierer - aber die sind auch nicht das Thema (Stichwort: Vorsatz vs. Fahrlässigkeit).

    👍 😮 habs gerade in Eclipse ausprobiert, der Compiler schluckt es!

    klar, mit dem doppelcast nimmste dem compiler die möglichkeit sich zu beschweren, aber versuch mal, deine so trickreich gecastete referenz zu benutzen...
    bereits die zeile nach dem cast wird schon nicht mehr ausgeführt.
    wäre es ein C++ programm (siehe mein beispiel oben), dann ginge es trotzdem. 😃

    tntnet schrieb:

    💡 Das geht auch einfacher ( ⚠ aber nie so benutzen ⚠ und wenn doch, dann nicht verraten, daß ich es gesagt habe):

    #define private public
    #include <einfremderheader.h>
    

    nicht jeder compiler lässt keywords in defines zu 😉

    tntnet schrieb:

    Es gibt manchmal Spezialfälle, wo ich mich über gewisse Schutzmechanismen hinweg setzten möchte. Und das geht mit C++.

    wie war das doch mit 'aus der not eine tugend machen' 😉
    eine programmiersprache, die es erlaubt die eigenen schutzmechanismen zu umgehen, hat im endeffekt gar keine schutzmechnismen
    🙂



  • pale dog schrieb:

    klar, mit dem doppelcast nimmste dem compiler die möglichkeit sich zu beschweren, aber versuch mal, deine so trickreich gecastete referenz zu benutzen...
    bereits die zeile nach dem cast wird schon nicht mehr ausgeführt.
    wäre es ein C++ programm (siehe mein beispiel oben), dann ginge es trotzdem.

    Nö, ich habs ausprobiert. Der Compiler kompiliert die nachfolgende Zeile ohne Probleme.

    Birne birne = new Birne();
    Apfel apfel = (Apfel) (Object) birne;
    apfel.toString();
    


  • Artchi schrieb:

    Nö, ich habs ausprobiert. Der Compiler kompiliert die nachfolgende Zeile ohne Probleme.

    Er kompiliert, wird sich aber mit ner Exception beschweren wenn du den faulen Apfel benutzen willst.



  • pale dog schrieb:

    Artchi schrieb:

    CStoll schrieb:

    Ja, wer böswillig sein will, geht sicher auch noch den Schritt weiter und schreibt Apfel a = (Apfel)(Object)eineBirne; (und wenn mich meine Erinnerung nicht täuscht, sollten beide Casts problemlos vom Compiler geschluckt werden). Und selbst wenn es keine Entsprechung zu reinterpret_cast<> in Java gibt, bleiben immer noch Angriffsmöglichkeiten für einen böswilligen Programmierer - aber die sind auch nicht das Thema (Stichwort: Vorsatz vs. Fahrlässigkeit).

    👍 😮 habs gerade in Eclipse ausprobiert, der Compiler schluckt es!

    klar, mit dem doppelcast nimmste dem compiler die möglichkeit sich zu beschweren, aber versuch mal, deine so trickreich gecastete referenz zu benutzen...

    Mit deinem ekligen C-Style Cast hast du auch nicht viel anderes gemacht, als den Compiler ruhigzustellen.

    tntnet schrieb:

    Es gibt manchmal Spezialfälle, wo ich mich über gewisse Schutzmechanismen hinweg setzten möchte. Und das geht mit C++.

    wie war das doch mit 'aus der not eine tugend machen' 😉
    eine programmiersprache, die es erlaubt die eigenen schutzmechanismen zu umgehen, hat im endeffekt gar keine schutzmechnismen
    🙂

    Da sind wir wieder beim Konflikt "Vorsatz vs. Fahrlässigkeit" - wer vorsätzlich handelt, kann so ziemlich jeden Schutzmechanismus der Sprache aushebeln (ich bin sicher, es gibt auch Mittel und Wege, um unter Java die privaten Member einer fremden Klasse zu manipulieren). Fahrlässigkeit betrifft dagegen Leichtsinnsfehler - und gegen sowas sollte einen der Compiler eigentlich schützen (ein Beispiel für einen solchen Schutz ist die Const-Correctness - wenn ich es sage, sollte ein Kollege auf direktem Weg auch nichts an meinen Objekten ändern dürfen).



  • Artchi schrieb:

    pale dog schrieb:

    klar, mit dem doppelcast nimmste dem compiler die möglichkeit sich zu beschweren, aber versuch mal, deine so trickreich gecastete referenz zu benutzen...
    bereits die zeile nach dem cast wird schon nicht mehr ausgeführt.
    wäre es ein C++ programm (siehe mein beispiel oben), dann ginge es trotzdem.

    Nö, ich habs ausprobiert. Der Compiler kompiliert die nachfolgende Zeile ohne Probleme.

    Birne birne = new Birne();
    Apfel apfel = (Apfel) (Object) birne;
    apfel.toString();
    

    ja, sicher, ich meinte ja auch 'ausgeführt'...
    wenn du das programm startest bekommst du in der zeile mit dem versuchten 'casting-exploit' eine 'ClassCastException', und das programm verabschiedet sich mit dem gefürchteten Java stacktrace.
    ...und eben da liegt der unterschied, ein gleichartiger angriff auf die security-features von C++ hat grosse aussicht auf erfolg!
    🙂



  • Vorausgesetzt, in C++ käme überhaupt jemand auf die Idee Äpfel und Birnen von der gleichen Basis abzuleiten, würde ein dynamic_cast (und nichts anderes repräsentiert der Java-Cast) einer Birne über die Basisklasse auf einen Apfel in C++ eine bad_cast Exception werfen. Nix mit Erfolg hier 😉



  • Wenn ich das Programm erst starten muß, um zu sehen ob es funktioniert, dann ist es zu spät.
    Wo ist da jetzt der Vorteil ggü. C++???



  • pale dog schrieb:

    ja, sicher, ich meinte ja auch 'ausgeführt'...
    wenn du das programm startest bekommst du in der zeile mit dem versuchten 'casting-exploit' eine 'ClassCastException', und das programm verabschiedet sich mit dem gefürchteten Java stacktrace.
    ...und eben da liegt der unterschied, ein gleichartiger angriff auf die security-features von C++ hat grosse aussicht auf erfolg!
    🙂

    Es geht hier nicht um security-features oder exploit. Private-, protected- und public-specifier sind Sprachfeatures, haben aber mit security gar nichts zu tun. Egal in welcher Sprache. Es ist kein Zugriffsschutz in dem Sinne, wie z. B. Dateisysteme ihn bieten. Daher kann man hier nicht von einem exploit sprechen. Höchstens von unsauberen Code, welcher sich nicht an Konventionen hält. Ich kann schliesslich auch in C so etwas ähnliches realisieren. Nur unterstützt mich C dabei einfach weniger, als C++ oder Java.

    Ansonsten kann ich (wieder mal) Artchi nur unterstützen und auch der Erfahrungsbericht von Simon2 bestätigt, daß eine Überprüfung zur Compilezeit in jedem Fall zu bevorzugen ist. Zur Laufzeit ist ein solches Feature nicht brauchbar. Laufzeitfehler verursachen einen wesentlich höheren Aufwand als Compilezeitfehler. Es ist schon in kleineren Projekten fast unmöglich, in Tests alle Codeteile unter allen Ausgangsbedingungen auszuführen, geschweige denn zu testen.



  • LordJaxom schrieb:

    ...ein dynamic_cast (und nichts anderes repräsentiert der Java-Cast) einer Birne über die Basisklasse auf einen Apfel in C++ eine bad_cast Exception werfen. Nix mit Erfolg hier 😉

    doch erfolg. 😉
    der böswillige (oder schlampige) coder nimmt einfach 'static_cast' oder die C-like casts.

    Artchi schrieb:

    Wenn ich das Programm erst starten muß, um zu sehen ob es funktioniert, dann ist es zu spät.

    gibts du deine programme weiter, ohne sie mal selbst gestartet zu haben 😕

    Artchi schrieb:

    Wo ist da jetzt der Vorteil ggü. C++???

    der vorteil ist folgender: das Java programm arbeitet entweder richtig oder gar nicht. ein C++ programm, das derart frisiert wird, kann die merkwürdigsten und u.u. gefährlichsten dinge anstellen, ohne das irgendwas auffällt...

    tntnet schrieb:

    Ich kann schliesslich auch in C so etwas ähnliches realisieren. Nur unterstützt mich C dabei einfach weniger, als C++ oder Java.

    klar, aber C erhebt nicht den geringsten anspruch, irgendwelche schutzmechanismen zu haben (ausser diesem 'const' vielleicht) ...

    tntnet schrieb:

    Laufzeitfehler verursachen einen wesentlich höheren Aufwand als Compilezeitfehler. Es ist schon in kleineren Projekten fast unmöglich, in Tests alle Codeteile unter allen Ausgangsbedingungen auszuführen, geschweige denn zu testen

    da bin ich ganz deiner meinung.
    trotzdem ist es wichtig, wenn die laufzeitumgebung fehler entdecken kann, die dem compiler (ob nun sie nun absichtlich verschleiert wurden oder nicht) entgangen sind und das programm killt, bevor schlimmeres passiert.
    und diese fehlererkennung sollte sich nicht nur beschränken auf 'division durch 0' und 'pointerzugriffe ins nirvana'.
    btw: sowas ist keineswegs neu, z.b. erkennt der kernel von windoows fehlersituationen, wie etwa zugriff auf den paged pool aus einer interruptroutine etc, und reagiert mit einem 'blue screen'.



  • pale dog schrieb:

    LordJaxom schrieb:

    ...ein dynamic_cast (und nichts anderes repräsentiert der Java-Cast) einer Birne über die Basisklasse auf einen Apfel in C++ eine bad_cast Exception werfen. Nix mit Erfolg hier 😉

    doch erfolg. 😉
    der böswillige (oder schlampige) coder nimmt einfach 'static_cast' oder die C-like casts.

    Wie gesagt, ein böswilliger Angreifer wird auch etwas finden, um eine Birne manipulieren zu können, die du ihm gibst (nur sieht dessen ansatz vermutlich etwas anders aus).

    Artchi schrieb:

    Wenn ich das Programm erst starten muß, um zu sehen ob es funktioniert, dann ist es zu spät.

    gibts du deine programme weiter, ohne sie mal selbst gestartet zu haben 😕

    In einem fertigen Programm steht das ja auch nicht so direkt hintereinander - da können die einzelnen Anweisungen über das gesamte Programm verteilt sein und sich erst bemerkbar machen, wenn alle Module zusammengebaut werden. Da wünsche ich dir mal viel Spaß bei der Fehlersuche.

    Artchi schrieb:

    Wo ist da jetzt der Vorteil ggü. C++???

    der vorteil ist folgender: das Java programm arbeitet entweder richtig oder gar nicht. ein C++ programm, das derart frisiert wird, kann die merkwürdigsten und u.u. gefährlichsten dinge anstellen, ohne das irgendwas auffällt...

    Und wenn es nicht arbeitet, versuch' mal herauszufinden, wo die Birne eigentlich herkam, die du dort als Apfel deklariert hast 😉
    Und wer nur bösartig genug ist (und sich entsprechend gut mit der entsprechenden Sprache auskennt), wird es auch schaffen, Java aus der Balance zu bringen.



  • CStoll schrieb:

    Und wenn es nicht arbeitet, versuch' mal herauszufinden, wo die Birne eigentlich herkam, die du dort als Apfel deklariert hast 😉

    naja, deshalb spuckt die VM ja diesen schönen stack trace aus, wenn sie der meinung ist, das programm sollte sich besser verabschieden...

    CStoll schrieb:

    Und wer nur bösartig genug ist (und sich entsprechend gut mit der entsprechenden Sprache auskennt), wird es auch schaffen, Java aus der Balance zu bringen.

    nö, das geht nur mit hackermethoden, wie z.b. native code laden, der die VM korrumpiert oder sowas.
    das kann aber auch nicht jeder machen: http://java.sun.com/j2se/1.5.0/docs/guide/security/spec/security-spec.doc1.html
    🙂



  • OK, in Java kann man mir schlechter vorsätzlich das Design kaputtmachen (obwohl - ein Cast von Point nach MutablePoint funktioniert und hat den selben Effekt wie ein const_cast<> in C++ Code). Aber dafür ist es umso leichter, fahrlässig das Programm zu zerlegen (und erfordert Aufwand, halbwegs const-korrekte Programme zu bauen).

    Wie willst du bitte Point nach MutablePoint casten? Point und MutablePoint sind Brüder, und Horizontal kannst du nicht casten. Gut kompilieren kannst du es, es kommt aber ClassCastExeptions.
    Es gibt ja in Java nicht umsonst instanceof.



  • pale dog schrieb:

    CStoll schrieb:

    Und wenn es nicht arbeitet, versuch' mal herauszufinden, wo die Birne eigentlich herkam, die du dort als Apfel deklariert hast 😉

    naja, deshalb spuckt die VM ja diesen schönen stack trace aus, wenn sie der meinung ist, das programm sollte sich besser verabschieden...

    Und was machst du, wenn der passende 'new Birne' Aufruf gar nicht im aktuellen Stack-Trace liegt? Kann ja sein, daß die Birne vor Stunden schon in einen Container gepackt wurde und nun als Object von dort geholt wurde 😉

    CStoll schrieb:

    Und wer nur bösartig genug ist (und sich entsprechend gut mit der entsprechenden Sprache auskennt), wird es auch schaffen, Java aus der Balance zu bringen.

    nö, das geht nur mit hackermethoden, wie z.b. native code laden, der die VM korrumpiert oder sowas.

    Und deinen reinterpret_cast<> zählst du nicht als "Hackermethode"?

    @DEvent: Sorry, ich hatte die letzten Entwürfe eurer const-Correctness Ansätze nicht mehr im Kopf. Ich meinte natürlich den Cast von PointInterface (den die Javaner extra eingeführt haben, um MutablePoint const-korrekt zu machen) nach Point.


Anmelden zum Antworten