Heap beschädigt nach sprintf_s



  • SeppJ schrieb:

    Selbst wenn der Wert von sOpenURL am Blockbeginn noch nicht feststeht, dann solltest du ihm nicht grundlos einen Wert zuweisen, bevor es seinen eigentlichen Wert bekommt.

    Was ist schlecht daran ? Ich meine, außer das es CPU Zeit kostet.

    SeppJ schrieb:

    Warum eigentlich 1024? Es gibt doch keine Maximallänge für URLs.

    Das Problem war, dass ich nicht wusste, wie ich am besten die Gesamtlänge der verwendeten URL berechne. Diese besteht ja aus mindestens 3 Einzelstrings. Alle Methoden dazu kamen mir recht aufwändig und zeitintensiv vor. Daher hab ich der Einfachheit halber einen Wert genommen, welcher in der Praxis kaum erreicht wird. Zu dem Zeitpunkt war es mir wichtiger, Erfolge zu erzielen um motiviert zu bleiben - die Schwachstellen könnte man hinterher noch ausbessern.

    (Dynamische allokierung steht auf der ToDo.)

    SeppJ schrieb:

    Ich hoffe, du prüfst auch immer brav die Rückgabewerte?

    Steht auf der ToDo Liste 😃



  • Pyro Phoenix schrieb:

    Was ist schlecht daran ? Ich meine, außer das es CPU Zeit kostet.

    Ein guter Compiler würde den Ausdruck vielleicht sogar ganz entfernen, weil er sieht, dass danach wieder eine unbedingte Zuweisung erfolgt. Da hättest du keine Probleme mit der CPU-Zeit.

    1. Grund: es ist einfach unnötig.
    2. Grund: du hast mehr Code.
    3. Grund: es kann die Fehleranfälligkeit erhöhen, wenn du einen Ausdruck hast, den der Compiler nicht wegoptimieren kann (z.B. ein memset auf 0 vor jedem strxxx-Call - ich reviewe gerade eine Software, wo die Programmier aus weiß Gott welchen Gründen immer memset machen), und da hast du dann gegebenenfalls eine fehlerhafte Länge drin und schreibst in Speicher, in den du gar nicht schreiben willst. Ist dir ja bereits passiert.

    Pyro Phoenix schrieb:

    Das Problem war, dass ich nicht wusste, wie ich am besten die Gesamtlänge der verwendeten URL berechne. Diese besteht ja aus mindestens 3 Einzelstrings. Alle Methoden dazu kamen mir recht aufwändig und zeitintensiv vor. Daher hab ich der Einfachheit halber einen Wert genommen, welcher in der Praxis kaum erreicht wird. Zu dem Zeitpunkt war es mir wichtiger, Erfolge zu erzielen um motiviert zu bleiben - die Schwachstellen könnte man hinterher noch ausbessern.

    Faustregel, nach denen ich programmiere: wenn ich es JETZT nicht fixe, ein dickes, fettes "TODO:" vor die Funktion schreiben, und dann vor jedem Commit frep 'TODO:' -r src/ machen, oder SOFORT fixen.

    Zur Information.



  • Wenn dein Heap beschädigt ist, solltest du ihn erst mal reparieren, bevor du weiter machst. Du kannst nämlich erst mal nicht unterscheiden, ob dein Programm wegen falschem Code abstürzt oder weil halt dein Heap hinüber ist.
    Du kannst deinen Heap fixen, in dem du mit memset deinen Heap mit Nullen über deinen kompletten Adressraum schreibst. Allerdings musst du hier im Kernelmode sein, da du nicht ausschließen kannst, dass durch eine fehlerhafte Bereichsgrenzenüberprüfung vom Betriebssystem, nicht ebenfalls andere Teile vom Heap beschädigt wurden. Treiber sind i. d. R. im Kernelmode.
    Unter Linux schau dir folgenden Link an:

    ftp://tm.informatik.uni-frankfurt.de/pub/papers/ir/kernelbook.pdf

    Falls du Windows benutzt, wird das etwas komplizierter, da Windows einen Hybridkernel besitzt. Du wirst nur den monolithischen Teil des Kernels bereinigen können. Das ist auch der Grund, weshalb Windows allgemein als instabiler gilt, weil wenn erst mal der Heap vom Mikrokernel beschädigt ist, hast du als End-Anwender kaum noch Chancen ihn zu bereinigen. Du brauchst dazu richtig teure Software, die über Sicherheitslücken auch den Hybridkernel erreichen. Diese Lücken, die jedoch immer wieder von MS geschlossen werden, müssen teilweise teuer im Schwarzmarkt erkauft werden. Das ist auch der Grund, weshalb die Software so teuer ist.
    Aber schau dir trotzdem mal vorerst folgenden Link an und wenn du nicht weiterkommst, kannst du dich immer noch melden:
    http://msdn.microsoft.com/en-us/library/windows/hardware/ff553208(v=vs.85).aspx

    Ein ähnliches Problem hast du übrigens auch bei Mac OS X. 😕 Das Vorgehen ist hier analog.

    L. G.,
    IBV



  • @IBV: Wieso musste ich bei deinem Post direkt an die Supercodes von autoexe.bat denken ... :p



  • dachschaden schrieb:

    @IBV: Wieso musste ich bei deinem Post direkt an die Supercodes von autoexe.bat denken ... :p

    Weiss nicht. Sagt mir nichts. 🙂



  • IBV schrieb:

    dachschaden schrieb:

    @IBV: Wieso musste ich bei deinem Post direkt an die Supercodes von autoexe.bat denken ... :p

    Weiss nicht. Sagt mir nichts. 🙂

    http://www.c-plusplus.net/forum/41456

    Betreibst super Satire 👍



  • Hab grad nochmal ein wenig nach einer simplen Lösung für die zusammengesetzten Strings gesucht. Ab C99 gäbe es ja eigentlich folgende Lösung:

    dStringLaenge = snprintf (NULL, 0, "%s, %s", sStringA, sStringB);
    

    Leider Befindet sich Visual Studio noch in der Steinzeit was C anbelangt - kein C99 Support.

    Microsoft bietet aber eine hauseigene Lösung: _snprintf (Identisch zum C99 Pendant - nur ohne garantierten Null Terminator)

    Habe zur Bestimmung der String-Länge und der anschließenden allokierung nun folgenden Code zusammengeschrieben:

    char	sStringA[] = "Hallo Welt";
    char	sStringB[] = "Variabler Text";
    char	*sStringC;
    int		dStringLaenge = 0;
    
    dStringLaenge = _snprintf (NULL, 0, "%s, %s", sStringA, sStringB);
    sStringC = calloc (dStringLaenge + 1, 1);
    sprintf (sStringC, "%s, %s", sStringA, sStringB);
    printf (sStringC);
    free(sStringC);
    

    Funktioniert so wie es soll - Problem dabei: Microsoft only !


  • Mod

    Du koenntest per ifdef und defines eine Loesung fuer beide Plattformen (C99 faehig vs. C89 + _snprintf) machen, wenn dir der Aufwand das Wert ist.



  • Ob da strlen und etwas Zugabe nicht ausricht?



  • Funktioniert so wie es soll - Problem dabei: Microsoft only !

    Dann verwende doch gleich _scprintf bzw. _vscprintf. Außerdem bei VS2015 gibt es snprintf .

    Einige Standard-C-Bibliotheken für Linux oder BSD haben übrigens asprintf, welches ich verwenden würde und für mich portabel genug ist. Wo sie fehlt, nimmt man sich eine bereits existierende Implementierung oder schreibt sie sich selbst.



  • DirkB schrieb:

    Ob da strlen und etwas Zugabe nicht ausricht?

    Theoretisch schon - allerdings ist das bei mehreren Strings recht unhandlich und bläht den Code auf, da ja jeder einzelne String einer separaten Anweisung bedarf. Bei _snprintf geschieht das in einem Rutsch.

    EinGast schrieb:

    Außerdem bei VS2015 gibt es snprintf .

    Ja, weil es seit C++11 Standard ist. Leider wird es in den älteren IDEs (VS2010) nicht nachträglich hinzugefügt.


Anmelden zum Antworten