Valgrind meldet: Use of uninitialised value



  • Mist, ich kanns auch nicht mehr nachvollziehen! Oo
    Ich schaus mir die Tage mal wieder an...

    L. G.
    Steffo


  • Mod

    TyRoXx schrieb:

    Kann ich mit GCC auf Ubuntu 11.10 nicht reproduzieren.

    Ich ebenfalls nicht (vergleichbares System).

    Da valgrind normalerweise nicht so krasse Fehler macht, vermute ich mal, dass du dein Beispiel zu stark gekürzt hast oder eventuell das falsche Programm gemessen hast (z.B. versehentlich das Originalprogramm gemessen, nicht das Minimalbeipsiel) .



  • Steffo schrieb:

    #include <stdlib.h>
    
    typedef struct {
    	unsigned long *elems;
    } ulstack;
    
    int main()
    {
    	ulstack stack;
    
    	stack.elems = NULL;
    
    }
    
    ...
    Uninitialised value was created
    ...
    

    Ändere mal in

    ulstack stack = {0};
    

    dann sollte zumindest diese Warnung verschwinden.



  • Mein Fehler war letztendlich, dass ich mit der GCC-Option static kompiliert habe (Copy & Paste aus einem alten Projekt). Ich vermute, dass einer der statisch inkludierten Bibliotheken den Fehler ausgelöst hat, denn ohne static klappt alles wunderbar!

    Dennoch danke für die Antworten!

    L. G.
    Steffo


  • Mod

    Wenn du mit static linkst, dann siehst du die Fehler aus den Systembibliotheken (die glibc hat ein paar bekannte, aber harmlose, valgrind-Fehler), die dann nicht mehr unterdrückt werden können, da nicht mehr ersichtlich ist, woher der Code kommt.



  • Das war auch meine Vermutung, wobei mich das aus mehrerer Hinsicht schon erstaunt hat, weil das ist für die natürlich höchst verwirrend, die ihre libs verwenden und andererseits spricht das nicht unbedingt für Qualität...


  • Mod

    Steffo schrieb:

    Das war auch meine Vermutung, wobei mich das aus mehrerer Hinsicht schon erstaunt hat, weil das ist für die natürlich höchst verwirrend, die ihre libs verwenden und andererseits spricht das nicht unbedingt für Qualität...

    Umgekehrt. Die Autoren sind so gut, sie wissen was diese Fehler bedeuten und sie wissen, dass es keine echten Fehler sind, aber dass der Code dadurch ein paar Takte effizienter ist.



  • Sowas kriegt man im Umgang mit Structs schon mal, ohne wirkliche Fehler zu machen. Beispielsweise erzeugt

    #include <stdio.h>
    #include <string.h>
    
    struct foo {
      int x;
      double y;
    };
    
    int main(void) {
      struct foo f, g;
    
      f.x = 1;
      f.y = 2.0;
    
      memcpy(&g, &f, sizeof(struct foo));
    
      if(memcmp(&f, &g, sizeof(struct foo)) == 0) {
        puts("Hurra!");
      }
    
      return 0;
    }
    

    bei mir diesen Fehler/diese Warnung, weil zwischen f.x und f.y etwas Padding liegt, das Valgrind völlig zu recht für uninitialisiert hält und moniert - er kann halt nur nicht erkennen, dass der Wert an dieser Speicherstelle völlig gleichgültig ist.



  • Würdet ihr da ein memset machen oder den Fehler hinnehmen?
    Mich würde das einfach bei der Fehlersuche stören, d. h. die richtigen Fehler von den nicht wirklichen Fehler zu unterscheiden. Ich würde daher eher zu einem memset tendieren, dann meldet valgrind auch keine Fehler mehr.

    L. G.
    Steffo



  • Ich würde meistens wohl den Vergleich nicht per memcmp machen - der Wert des Paddings ist ja für die logische Äquivalenz zweier Variablen eines Struct-Typs überhaupt nicht von Interesse.

    Ansonsten ist dort, wo man sich von Verhalten, das Valgrind bemängelt, einen Vorteil verspricht, "valgrind --gen-suppressions" ein Freund.


  • Mod

    Steffo schrieb:

    Würdet ihr da ein memset machen oder den Fehler hinnehmen?
    Mich würde das einfach bei der Fehlersuche stören, d. h. die richtigen Fehler von den nicht wirklichen Fehler zu unterscheiden. Ich würde daher eher zu einem memset tendieren, dann meldet valgrind auch keine Fehler mehr.

    Bei einem einfachen unkritischen Programm würde ich das wohl auch machen. Aber wenn ich eine hochkritische Systembibliothek schreibe, dann würde ich es ganz bewusst nicht tun. Denn schließlich würde diese Entscheidung Millionen von Computern mit Millionen verschiedener Anwendungsszenarien betreffen. Und dann ist ein gesparter Takt ein gesparter Takt auf Millionen von Rechnern, jeweils millionenfach, Tag für Tag. Da wäre mir herzlich egal, dass ein dummes Debugprogramm da einen false-positive hat.



  • das memcmp ist ja kein false positive. Wenn da uninitialisierte padding bytes verglichen werden ist das Programmverhalten auch falsch.



  • In diesem Fall ist zwar nicht sichergestellt, welchen Wert das Padding hat, aber es ist nach memcpy sichergestellt, dass es in f und g den gleichen Wert hat. Das Verhalten ist da wohldefiniert, auch wenn uninitialisierter Speicher benutzt wird.



  • stimmt, habe ich jetzt genau wie valgrind verrafft.

    Aber ich sehe noch nicht, wo man jemals so ein memcmp benutzen möchte... wenn Teile der verglichenen Werte zuƒällig entstanden sind, kann man doch auch nicht gescheit vergleichen?


  • Mod

    Werte entstehen aber nicht zufällig. Das sieht vielleicht für ein Anwendungsprogramm so aus, aber ein Systemcall im Startupcode kann sich da drauf verlassen, als erster auf frisch genullten Speicher zuzugreifen. Die Überreste dieser Aufrufe sind es, wegen derer selbst bei einem frisch gestarteten Programm nicht alle Variablen mit 0 starten.

    Außerdem können da durchaus auch noch andere Fehler sein. Das Beispiel demonstriert doch schön, dass es false-positives geben kann und dass die Behebung ein kleines bisschen Performance kosten würde. Und valgrind-Sauberkeit gegen Performance wäre in diesem Fall ein schlechter Tausch. Man kann sicherlich noch mehr Beispiele finden (bin aber gerade zu müde). Oder mal im Quellcode gucken, die glibc, die hier die konkreten Fehler verursacht hat, ist schließlich nicht geheim.



  • SeppJ schrieb:

    ...
    Denn schließlich würde diese Entscheidung Millionen von Computern mit Millionen verschiedener Anwendungsszenarien betreffen. Und dann ist ein gesparter Takt ein gesparter Takt auf Millionen von Rechnern, jeweils millionenfach, Tag für Tag. Da wäre mir herzlich egal, dass ein dummes Debugprogramm da einen false-positive hat.

    Wie stehst du eigentlich zu Mikrokernel, Sicherheitssoftware, OpenBSD etc.?


  • Mod

    Steffo schrieb:

    SeppJ schrieb:

    ...
    Denn schließlich würde diese Entscheidung Millionen von Computern mit Millionen verschiedener Anwendungsszenarien betreffen. Und dann ist ein gesparter Takt ein gesparter Takt auf Millionen von Rechnern, jeweils millionenfach, Tag für Tag. Da wäre mir herzlich egal, dass ein dummes Debugprogramm da einen false-positive hat.

    Wie stehst du eigentlich zu Mikrokernel, Sicherheitssoftware, OpenBSD etc.?

    Ich meine, wenn du denkst, dass meine Meinung hierzu relevant wäre, dann hast du meine Erklärung (absichtlich?) nicht verstanden.



  • Ich kann mir nur schwer vorstellen, dass Software, die extrem auf Sicherheit optimiert sind, auch nur eine Warnung zulässt. Soll jemand, der die libc verwendet, extra im Quellcode nachgucken, um zu schauen, wie sicherheitsrelevant der Fehler ist? Er würde eher zu einer Alternative wechseln (vielleicht libc von OpenBSD?).


  • Mod

    Ich kann mir nur schwer vorstellen

    Ich sag mal so: Deswegen lässt man dich keine Entscheidungen treffen.

    Der Thread ist ins extreme Offtopic abgedriftet. Wenn du deine geringe Vorstellungskraft oder Unverständnis der Sachlage weiterhin öffentlich kundtun möchtest, dann kannst du einen passenden Diskussionsthread dazu in TrudPC aufmachen.


Anmelden zum Antworten