[C++] new

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Original von klausel
    Das war genau die Frage. malloc nullt nix. new könnte ja ein schlauer Wrapper für malloc sein, der direkt alles nullt.

    1) PODs haben keinen DefaultConstuctor
    2) Sonst werden PODs auch nicht genullt, warum auf einmal bei new?
  • Also, abgesehen davon, dass Klaus sicherlich dafür wäre, dass jede Instanz (also auch skalare) genullt wird (das unterstelle ich jetzt mal), rechtfertigt sich das abweichende Verhalten daraus, dass es in der Wildnis nuneinmal ganz enorm viele Probleme mit Arrays gibt. Man kann das jetzt schön theoretisieren. Das ändert aber nichts daran, dass es diese Probleme gibt.

    Du musst das dann natürlich für jede Klasse ändern, was nicht unerheblich Aufwand ist. Eine Alternative wäre eine Kategorie von NSObject. Dann hat man die Arbeit nur einmal …
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von tjp
    Wie gesagt, wenn man es unbedingt braucht kann man es einbauen. Nur diesen Aufwand für PODs zu betreiben ist etwas übertrieben. Ich sehe persönlich auch keine Grund warum auf einmal new PODs nullen sollte. Sonst werden PODs auch nicht genullt. Warum dann auf einmal dieses abweichende Verhalten haben wollen?


    Jungs ... ich habe gefragt, ob new automatisch nullt, weil ich es nicht wusste. Mehr nicht. Da meine Frage seit drei Stunden beantwortet ist, ist das Thema doch eigentlich durch, oder? ;)

    Mann, Mann, Mann ...
  • Auch wenn die Frage des OP schon lange beantwortet ist, muss ich mich jetzt trotzdem nochmal kurz zu Wort melden, um einiges richtig zu stellen.

    Original von tjp
    Meist nutzt man new auf PODs um Speicher für irgend was zu allozieren und schreibt anschließend gleich Daten rein. Warum den Job gleich zweimal machen?

    Absolut richtig. Genau das ist eben die Philosophie von c++: Es wird nichts automatisch gemacht, was man nicht auch haben will. Wenngleich Exception-Handling hier eine Ausnahme der Regel darstellt.

    Original von Tom9811
    Ich kann auch kein Problem erkennen, wie 0 interpretiert wird. Dann mag es anders interpretiert werden. Es wird indessn *definiert* interpretiert, egal ob 0x0 nun 0 oder Damenuntrwäsche bedeutet.

    Das ist in der Tat kein Problem, doch es hilft Dir (bis auf beim debuggen) auch nicht weiter. Du kannst im Programm mit einem Test, ob ein Element gleich "0" ist nämlich nicht erkennen, ob auch eine binäre 0 dahinter steht, also Dein Element noch nicht anderweitig initialisiert wurde.

    Original von Tom9811
    Also, abgesehen davon, dass Klaus sicherlich dafür wäre, dass jede Instanz (also auch skalare) genullt wird (das unterstelle ich jetzt mal),

    eine sehr gewagte These...
    rechtfertigt sich das abweichende Verhalten daraus, dass es in der Wildnis nuneinmal ganz enorm viele Probleme mit Arrays gibt.

    Diese Probleme haben aber nicht viel damit zu tun, ob der Speicher genullt wird, oder nicht.

    Du musst das dann natürlich für jede Klasse ändern, was nicht unerheblich Aufwand ist.

    Nö, man kann auch den globalen new-Operator überschreiben.
    Eine Alternative wäre eine Kategorie von NSObject. Dann hat man die Arbeit nur einmal …

    Äh, wir sind aber schon noch bei c++, oder?

    Also nochmal kurz: Egal ob POD oder nicht POD, man kann den Speicher vorher nullen. Dennoch sind die Werte der POD-Variablen hinterher undefiniert. Für andere Daten wird sowieso der DC aufgerufen, was die Nullung erst recht überflüssig macht.
  • Na ja, richtig stellen:
    Das ist in der Tat kein Problem, doch es hilft Dir (bis auf beim debuggen) auch nicht weiter. Du kannst im Programm mit einem Test, ob ein Element gleich "0" ist nämlich nicht erkennen, ob auch eine binäre 0 dahinter steht, also Dein Element noch nicht anderweitig initialisiert wurde.

    Das stimmt etwa nicht. Es hilft mir beim Debugging *sehr* viel weiter, wenn der Fehler definiert ist. Äußert sich der Fehler etwa nur, wenn eine Zahl zufällig ungerade ist, dann habe ich überhaupt nur eine 50 %ige Debugging-Wahrhscinelichkeit. In der Praxis ist es aber komplexer: Da taucht dann der Fehler überhaupt nur bei jeden 10. oder 20. Progammlauf auf.

    Dafür ist es mir ziemlich egal, was 0 bedeutet. Es ist sogar egal, ob genullt wird. Man kann jedes x-beliebige Pattern reinschreiben, wenn es nur *definiert* ist.
    eine sehr gewagte These...

    Nein, die These ist nicht gewagt, sondern naheliegend. Ich weiß, was Klaus macht.

    Diese Probleme haben aber nicht viel damit zu tun, ob der Speicher genullt wird, oder nicht.
    Uninitialisierte Variablen sind ein klassischer Angriffsvektor. Auch hierzu wird dir Klaus sicherlich einiges erzählen können. Der wesentliche Angriff beruht darauf, dass du etwa durch einen Bufferoverflow an anderer Stelle die Variable selbst "initialisierst", etwa eine lokale Variable.


    Die Werte sind auch nicht nach einer Nullung undefiniert. Sie sind jedesmal gleich. Und sie sind niemals Werrte, die vorher an die Stelle geschmuggelt wurden.

    Das *macht* einen Unterschied.

    WIE ZUM BEWEISE sehe ich gerade in meiner Source das:

    Quellcode

    1. FightMO* fight;
    2. NSString* key;
    3. NSEnumerator* keysEnum = [fightDictionary keyEnumerator];
    4. while( (fight = [keysEnum nextObject]) ) {
    5. [self setValue:[fightDictionary objectForKey:key] forKey:key];
    6. }

    Na wunderbar! Ein Angreifer kann dafür sorgen, dass er irgendwann den (noch unbenutzten) Stack überschreibt, damit später key auf $IRGENDWAS zeigt. Damit kann er dann Werte in meinem Graphen setzen.

    Würde key initialisiert, wäre dieser Angriff nicht möglich. Wil ich das vermeiden, muss ich jede lokale Variable initialisieren.

    Quellcode

    1. FightMO* fight = nil;
    2. NSString* key = nil;
    Das dürte bei den meisten CPUs *deutlich* schlechter im Lauufzeitverhalten sein als ein automatisches Nullen des Stacks.

    Warum der Compiler allerdings nicht gemeckert hat …?
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von Tom9811
    Nein, die These ist nicht gewagt, sondern naheliegend. Ich weiß, was Klaus macht.

    Nagut, mag sein. Ich weiß nicht, was Klaus macht. Wie ich geschrieben habe kann er sich ja durch überschreiben des globalen new-Operators behelfen. Wenn man ein neues Projekt anfängt und der Code portierbar sein soll, sollte man davon allerdings die Finger lassen...


    Die Werte sind auch nicht nach einer Nullung undefiniert. Sie sind jedesmal gleich. Und sie sind niemals Werrte, die vorher an die Stelle geschmuggelt wurden.

    Aber nur solange Du auf der gleichen Maschine und beim gleichen Compiler bleibst.


    Uninitialisierte Variablen sind ein klassischer Angriffsvektor. Auch hierzu wird dir Klaus sicherlich einiges erzählen können. Der wesentliche Angriff beruht darauf, dass du etwa durch einen Bufferoverflow an anderer Stelle die Variable selbst "initialisierst", etwa eine lokale Variable.

    Da liegt die Ursache beim Bufferoverflow. Den verhinderst Du aber nicht durch initialisieren von Variablen. Du kannst damit in bestimmten Fällen die Symptome bekämpfen. Wenn der Bufferoverflow aber nach der Initialisierung der Variablen erfolgt, hast Du so oder so ein Problem.

    Eine mögliche Ursache für einen Bufferoverflow ist z.B. ein zu kleines Array. Daher sollte man statt Arrays nach Möglichkeit Container z.B. aus der STL verwenden. Aber wir schweifen vom Thema ab...


    WIE ZUM BEWEISE sehe ich gerade in meiner Source das:
    Na wunderbar! Ein Angreifer kann dafür sorgen, dass er irgendwann den (noch unbenutzten) Stack überschreibt, damit später key auf $IRGENDWAS zeigt. Damit kann er dann Werte in meinem Graphen setzen.

    In der Tat ein klassischer Fehler. Aber auch ohne Angriff hast Du hier undefiniertes Verhalten.

    Warum der Compiler allerdings nicht gemeckert hat …?

    Das wundert mich jetzt allerdings auch. Solche Fehler sollte der Compiler eigentlich erkennen und tut er bei mir in der Regel auch.


    Würde key initialisiert, wäre dieser Angriff nicht möglich.

    Kommt drauf an, an welcher Stelle der Angriff erfolgt. Solange der Stack von außen manipulierbar ist, hast Du auf jeden Fall ein potentielles Problem.



    Wil ich das vermeiden, muss ich jede lokale Variable initialisieren.

    Quellcode

    1. FightMO* fight = nil;
    2. NSString* key = nil;
    Das dürte bei den meisten CPUs *deutlich* schlechter im Lauufzeitverhalten sein als ein automatisches Nullen des Stacks.

    Du machst den Fehler damit eventuell sichtbarer. Beseitigen tust Du ihn aber nur, wenn Du key richtig initialisierst. Das initialisieren von Variablen mit einem bewusst ungültigen und vor allem überprüfbaren Wert ist außerdem durchaus legitim. Es ging aber ursprünglich darum, ob der Speicherbereich mit binären Nullen überschrieben werden sollte. Und nicht auf jeder Maschine ist binär 0 gleich nil. Dh. wenn das Dictionary bei nil eine Fehlerbehandlung durchführt, Du aber statt die Variablen mit nil initialisiert den Speicherbereich mit 0 überschrieben hättest, würde der gewollte Fehlerfall nicht unbedingt eintreten.

    Zum Thema Laufzeitverhalten: Wie war das noch mit Donald Knuth? Die meisten Compiler sind durchaus in der Lage entsprechende Optimierungen vorzunehmen.
  • Wie bereits ausgeführt, ist der Code nicht von Klaus. Er überprüft ihn.

    Wenn 0x0 auf unterschiedlichen Maschinen oder von untershciedlichen Compilern anders dargestellt wird, hast du ganz andere Probleme: Es fängt bereits beim Lesen der Dateien an.

    Es ist auch gleichgültig, ob nil 0x0 ist. Ich kannn das auch mit 0x54612923 initialisieren. Entscheidend ist, dass bei einem solchen Fehler der Programmlauf definiert ist, ich also denselben Fehler stets bekomme. Ich muss beim Debugging nicht hoffen, ihn gerade zu erwischen.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von klausel
    Original von eloso
    Nagut, mag sein. Ich weiß nicht, was Klaus macht.


    Hättest Du die bisherigen Postings aufmerksam gelesen, wüsstest Du es. :rolleyes:

    Dass Du fremde Software überprüfst, weiß ich auch. Aber um was für Software es sich handelt, wie sie geschrieben ist, und wie das/die Problem(e) konkret aussehen weiß ich alles nicht. Darüber hast Du auch nichts geschrieben. So, wie es sich angehört hat, weiß Tom mehr. Wenn er nicht mehr weiß, weiß ich nicht, wie er darüber urteilen kann, ob Du gerne einen Null-Überschreiber im new-Operator hättest.
  • Original von Tom9811
    Wie bereits ausgeführt, ist der Code nicht von Klaus. Er überprüft ihn.

    Das habe ich durchaus mitbekommen. Mein Ratschlag war auch allgemeiner Natur und nicht direkt auf Klaus aktuelles Problem bezogen.


    Wenn 0x0 auf unterschiedlichen Maschinen oder von untershciedlichen Compilern anders dargestellt wird, hast du ganz andere Probleme: Es fängt bereits beim Lesen der Dateien an.

    Genau da gibt es auch oftmals Probleme. Prominentestes Beispiel dürfte Big/Little-Endian sein (wobei da die 0 zufällig gleich ist)
  • Nein, das muss nicht zwingend ein Buffer-Overflow sein. Es kann auch durch gewolltes und geplantes Verhalten an anderer Stellle entstehen. Mal schmatisch:

    Quellcode

    1. (void)funtion1( … ) {
    2. function2( 4 );
    3. function3( sonstwas );
    4. }
    5. function2( int a ) {
    6. int code;
    7. scanf( "%d", &code );
    8. /* muss 0 oder 1 sein */
    9. switch( code ) {
    10. case 0:
    11. case 1:
    12. default:
    13. /* do nothing */
    14. }
    15. }
    16. function3( int b ) {
    17. int index;
    18. int buffer[ 5 ]
    19. while( index ) {
    20. buffer[ index ] = …
    21. index = …
    22. }
    23. }
    Alles anzeigen

    Der Programmierer testet seinen Code und gibt mal 0 ein, mal 1. Er gibt auch mal 3 ein. Alles läuft. Auch die 3 funktioniert, da die erste Anweisung im while zwar blödsinnig ist, aber keinen (erkennbaren) Schaden anrichtet. Sagen wir einfach, dass der Wert bei weiteren Iterationen sinnvoll überschrieben wird.

    Ein $BÖSER erkennt dieses Problem und übergibt nun in function2() einfach mal 3746287343. Das wird in function3() mit ziemmlicher Sicherheit zu einem Speicherzugriffsfehler fürhen: Software steht. Lass das einfach mal Code aus einem lebenswichtigen Dienst auf einem Server sein. Supi, das war es dann. Klingeln wir den Admin herbei, der den Dienst wieder startet – damit er gleich wieder seinen Dienst einstellt.

    Der Hacker freut sich dann doch, dass er so billig eine DoS-Attacke hinbekommen hat. Das ist auch eine Form der Performance!

    Ihc kann auch gerne dein Endianess-Problem aufgreifen. In function3() haben wir einen Charbuffer. Da in function2() nur Werte bis 10 möglich sind (wird ordentlich getestet, sorgfältiger Programmierer!) ist bei der richtigen Endianess der Puffer gleich initialisiert: [0x00, 0x00, 0x00, 0x09]. Bei einem Test fällt nichts auf. Auf einer anderen Maschine hat er indessen ein Zeichen: 0x09, 0x00, 0x00, 0x00]. Das verursacht dann den Absturz des Programmes. Noch Fragen, Kienzle?

    Klaus ist externer Sicherheitsberater. Er prüft sozusagen Server, Software etc. auf Angriffsmöglichkeiten. Dazu bedient er sich Standardtools (wofür er dann demnächst im Knast landet. ;-)) oder schaut sich eben Konfigurationen oder Sourcen an. Er kann daher nicht mal eben auf std:string umsteigen. Er kann nur sagen, dasss man auf std::string umsteigen sollte.

    Aber das Problem uninitialisierter Variablen wird dadurch nicht umgangen, siehe oben.

    Ich finde übrigens das Sicherheitsbewusstsein bemerkenswert. Eine Ansammlung von Aussagen

    a) Das ist performanter (Bestimmt, bestimmt! - Jedenfalls, bis man es überprüft hat.)
    b) Dann darf man das eben nicht machen bzw. muss aufpassen! (Menschen?)
    c) Von Sicherheitsproblemen weiß ich nichts.

    ist dafür verantwortlich, dass mein E-Mail-Postfach täglich mit Spam gefüllt ist. Tolle Performance! Nur richtig angewendet?
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von Tom9811
    Aber das Problem uninitialisierter Variablen wird dadurch nicht umgangen, siehe oben.

    C hat eine bestimmte Tradition Dinge zu lösen. Damit muß man leben, wenn man diese Programmiersprache nutzt. C++ oder Objective-C erlauben Klassen, die eine Kapselung und eine Abstraktion erlauben. Für LowLevel Aufgaben muß man entsprechende Klassen bauen, dann ist man halbwegs vor den größten Problemen abgesichert. Diese Klassen müssen entsprechend ausgetestet werden. Wenn man Codereview macht, dann muß man hier besonderen Augenmerk darauf werfen.

    Ich finde übrigens das Sicherheitsbewusstsein bemerkenswert. Eine Ansammlung von Aussagen

    a) Das ist performanter (Bestimmt, bestimmt! - Jedenfalls, bis man es überprüft hat.)
    b) Dann darf man das eben nicht machen bzw. muss aufpassen! (Menschen?)
    c) Von Sicherheitsproblemen weiß ich nichts.

    Wenn man Variablen verwendet, muß man diese initialisieren. Es bringt nichts, sie vorher mit einem Bitmuster zu überschreiben. Sie müssen so oder so mit den korrekten Werten initialisiert werden und darauf muß geschaut werden. Das ist auch die Design-Philosophie hinter C++.

    Die ISO-Norm garantiert das, was Du haben willst, nicht. Ergo, laufe ich Gefahr, daß ich mich in falscher Sicherheit wiege, wenn ich einfach Speicher via char* nulle, das ist noch schlimmer. Es gibt bekannte Wege die PODs korrekt zu initialisieren, diese und nur diese sollte man nutzen.

    ist dafür verantwortlich, dass mein E-Mail-Postfach täglich mit Spam gefüllt ist.

    Die Spam-Problematik hat wenig mit Fehlern in Applikationen zu tun. Der Fehler liegt im Protokoll, welches für die Mailübertragung genutzt wird! Einige Server lassen sich leichter mißbrauchen, weil es Software-Bugs gibt. Aber das ist nicht die Ursache für die Spamflut.
  • Original von tjp
    Die Spam-Problematik hat wenig mit Fehlern in Applikationen zu tun. Der Fehler liegt im Protokoll, welches für die Mailübertragung genutzt wird! Einige Server lassen sich leichter mißbrauchen, weil es Software-Bugs gibt. Aber das ist nicht die Ursache für die Spamflut.


    Genau
  • Die aktuelle Problematik beruht auf Botnetzen. Du hast lokal gar nicht die Leistungsfähigkeit, so viel Dosenfleisch zu produzieren.

    Ohne Windows (und die darinenthaltenen Lücken) gäbe es die derzeitige Spamproblematik nicht.
    heise.de/newsticker/meldung/90241
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Botnetze braucht man nur für DDOS Attacken, diese kann man aber auch mit 100% korrekter Software nicht verhindern. Eine DDOS-Attacke bringt immer den Rechner zu Fall, sofern genügend Bots benutzt werden.

    Wenn der Originalserver abgeschossen ist, kann man dem anderen Mailserver vorgaukeln, man sei das Original. Das funktioniert aber nur deshalb, weil das Mailprotokoll keine Authentifizierung beinhaltet, die sicherstellt, daß beide Partner auch die sind, die sie vorgeben zu sein. Ursächlich veranwortlich für das Problem Spam ist also das Mail Protokoll und keinerlei Softwarebug.
  • Original von tjp
    Botnetze braucht man nur für DDOS Attacken, diese kann man aber auch mit 100% korrekter Software nicht verhindern. Eine DDOS-Attacke bringt immer den Rechner zu Fall, sofern genügend Bots benutzt werden.

    Wenn der Originalserver abgeschossen ist, kann man dem anderen Mailserver vorgaukeln, man sei das Original. Das funktioniert aber nur deshalb, weil das Mailprotokoll keine Authentifizierung beinhaltet, die sicherstellt, daß beide Partner auch die sind, die sie vorgeben zu sein. Ursächlich veranwortlich für das Problem Spam ist also das Mail Protokoll und keinerlei Softwarebug.


    Mir scheint du bist über Botnetze nicht richtig informiert.
    Der Bot nistet sich auf deinem Rechner ein. Das geht nur über Sicherheitslücken. Dann wird unter deinem Namen über deinen Mailaccount Spam verschickt. Hat erstmal nichts mit dem Mailprotokoll zu tun. Dass da noch der ein oder andere schlecht administrierte Mailserver eine Rolle spielt ist nebensächlich.

    DDOS ist eine andere Sache. Ich sehe da die grossen Provider in der Pflicht, frag mich aber nicht wie.

    Chris
    Man macht einfach solange irgendwelche Dinge, bis man tot ist.
    Und dann bekommen die anderen Kuchen.
  • Original von Tom9811
    Ihc kann auch gerne dein Endianess-Problem aufgreifen. In function3() haben wir einen Charbuffer. Da in function2() nur Werte bis 10 möglich sind (wird ordentlich getestet, sorgfältiger Programmierer!) ist bei der richtigen Endianess der Puffer gleich initialisiert: [0x00, 0x00, 0x00, 0x09]. Bei einem Test fällt nichts auf. Auf einer anderen Maschine hat er indessen ein Zeichen: 0x09, 0x00, 0x00, 0x00]. Das verursacht dann den Absturz des Programmes. Noch Fragen, Kienzle?

    Nehmen wir mal an, der Stack würde genullt werden. Du testest - keine Probleme. Auf einer anderen Maschine wird die Folge binärer Nullen aber nun für int als 43423423 interpretiert. Das verursacht dann den Absturz des Programmes. Alles klar, Hauser?


    Klaus ist externer Sicherheitsberater. Er prüft sozusagen Server, Software etc. auf Angriffsmöglichkeiten. Dazu bedient er sich Standardtools (wofür er dann demnächst im Knast landet. ;-)) oder schaut sich eben Konfigurationen oder Sourcen an. Er kann daher nicht mal eben auf std:string umsteigen. Er kann nur sagen, dasss man auf std::string umsteigen sollte.

    Das erklärt natürlich einiges. Andererseits sollte er gerade dann froh sein, dass die Software so mies ist, sonst wäre er arbeitslos ;)

    Dass Variablen initialisiert werden müssen ist klar. Aber eben gleich richtig und nicht durch überschreiben mit Nullen.