Undefiniertes Verhalten (UB)



  • @Wade1234 sagte in Undefiniertes Verhalten (UB):

    man könnte auch vernünftig die sprache lernen, damit man solche fehler direkt sieht.

    Ich wage mal die Vermutung, dass es bei der Aufgabenstellung genau darum geht 🙄



  • @SeppJ sagte in Undefiniertes Verhalten (UB):

    @DirkB sagte in Undefiniertes Verhalten (UB):

    Der cast beim malloc (void* auf void*) sollte einem auch zu denken geben.

    Und dann noch stdlib.h einbinden.

    Nun, ohne das include von stdlib.h ist es ja ein Cast von int nach void*.

    Nein, veraltete Ansicht. Seit C99 gibts kein 'implicit int' mehr.

    Denn viel zu viele Lehrer können es einfach nicht richtig.

    Natürlich.


  • Mod

    @Wutz sagte in Undefiniertes Verhalten (UB):

    @SeppJ sagte in Undefiniertes Verhalten (UB):

    @DirkB sagte in Undefiniertes Verhalten (UB):

    Der cast beim malloc (void* auf void*) sollte einem auch zu denken geben.

    Und dann noch stdlib.h einbinden.

    Nun, ohne das include von stdlib.h ist es ja ein Cast von int nach void*.

    Nein, veraltete Ansicht. Seit C99 gibts kein 'implicit int' mehr.

    Korrekt, aber dummerweise übersetzen GCC, Clang, ICC, MSVC (und wahrscheinlich noch viele mehr) es trotzdem und warnen bloß. MSVC warnt noch nicht einmal.

    https://godbolt.org/z/fC6Ab2



  • @pcovc sagte in Undefiniertes Verhalten (UB):

    #include <stdio.h>
    #include <string.h>
    
    double convertTemperature(double* fahrenheit) {
    	double celsius = (*fahrenheit - 32)/1.8;
    }
    
    char* formatTemperature(double value, const char* unit) {
    	char result[10];
    	sprintf(result, "%f degree %s", value, unit);
    	return result;
    }
    
    int main() {
    	void* buffer = (void*)malloc(33);
    	strncpy(buffer, "enter a temperature in degree F: ", 33); //Kopiert 33 zeichen von "enter a...." in buffer.
    	printf("%s", buffer);
    
    	scanf("%f", buffer);
    	double celsius = convertTemperature(buffer);
    	printf("the temperatures is %s\n", formatTemperature(celsius, "C"));
    }
    
    
    • Zeile 15 weist ein undefiniertes verhalten auf, da man kein Typ definiert der den String entgegenimmt bei Zeile 16.
    • Zeile 17 gibt nicht das erwartete raus, da es keinen String bekommen hat
    • Zeile 19 möchte einen double obwohl buffer void ist und ein String übergeben bekommen hat.
    • Zeile 20 geben wir einen Array obwohl ein Pointer verlangt wird.
    • 21 führt zu einem UB, da in Zeile 9-11 ein Array genutzt wird obwohl die funktion sprintf ein Pointer möchte.

    Du (oder dein Lehrer und du jetzt auch) hast da völlig falsche Vorstellungen von UB.
    UB (undefined behavior) ist ein Fachbegriff aus dem C-Standard (http://www.iso-9899.info/n1570.html) und definiert das (Laufzeit)Verhalten eines Programms, das mit einem standardkonformen Compiler übersetzt wurde bei speziellen Quellcodesituationen.
    Für UB sind die dort alle detailliert aufgelistet und entweder explizit als UB gekennzeichnet oder implizit (mittels shall oder shall not).
    Was du hier machst ist das Pferd von hinten aufzuzäumen, denn o.g. UB-Situationen können in solche bufferoverflows münden, aber daraus zu schlußfolgern, dass alle bufferoverflows aus UB resultieren, ist laienhafter Unsinn.
    Ich tippe mal darauf, dass dein Lehrer irgendwo den Fachbegriff UB aufgeschnappt hat und meint, ihn verstanden zu haben und seine Schäfchen damit beglücken zu müssen.

    • Zeile15: ist vollkommen korrekt und niemals UB, obwohl kein C-Profi malloc casten würde
    • Zeile16: ist ebenso kein UB, obwohl kein C-Profi strncpy verwenden würde, zumindest nicht, wenn er in Betracht ziehen muss, dass jemand anderes als er selbst den Code warten muss; durch das implizite Anhängen von '\0' an den 33-Byte Speicher kommt es zu einem (sogar schreibenden) Zugriff auf undefinierten Speicher; gute Compiler produzieren hier Code, der vom Laufzeitsystem in segmentation fault o.ä. mündet; auch valgrind & Co. müssten sowas finden; abseits von UB im Standard gibt es aber (natürlich nur in Profiquellen und nicht beim Lehrer) best practices, die auf solche Fehlerquellen hinweisen http://www.cplusplus.com/reference/cstring/strncpy/; C-Profis haben sowas sämtlichst im Kopf, brauchen nicht nachzuschlagen und unterscheiden sich auch dadurch von selbsternannten Programmierprofis
    • Zeile17: kein UB, aber printf greift auch hier aus o.g. Gründen auf undefinierten Speicher zu (wenn auch nur lesend)
    • Zeile19: auch hier ist nirgendwo UB, buffer ist vom Typ void*, scanf verlangt hier float*; da void* aber zu allen Datenzeigertypen kompatibel ist, liegt kein UB vor; wenn hier was schiefgehen kann ist es, falls der malloc-Speicher kleiner sizeof(float) gewählt wurde, auch dann kommt es zum (schreibenden) Zugriff auf undefinierte Speicherbereiche, was aber der Standard mit UB gar nicht festlegt, weil es sich auch hier um Laufzeitverhalten handelt
    • Zeile20: kein UB; hier fehlt ja wohl das return in convertTemperature: gute Compiler warnen hier (dead code oder dergleichen)
    • Zeile21: kein UB; char[10] dürfte zu gering dimensioniert sein, sodass der schreibende Zugriff auf undefinierten Speicher schon vor dem return passiert; ansonsten ist die o.g. Compilermeldung natürlich korrekt

    Fazit: der C-Sprachstandard regelt mittels UB das Verhalten von Compilern in einzelnen Codesituationen, was sie zu tun oder zu lassen haben (im Falle von UB können die Compiler Code produzieren, wie sie wollen).
    Für allgemeine Programmiertipps ist der Standard der falsche Ort, der beschränkt sich (z.B. für bufferoverflows) nur auf allgemeine Ratschläge: Bounds-checking interfaces
    Der Standard regelt somit in erster Linie Vorschriften (UB u.a.) für Compilerbauer, nicht für Programmierer.



  • @Wutz sagte in Undefiniertes Verhalten (UB):

    Zeile17: kein UB, aber printf greift auch hier aus o.g. Gründen auf undefinierten Speicher zu (wenn auch nur lesend)

    Wie nennt sich denn das? Ist Lesen aus Speicher, der mir nicht gehört, nicht UB? Daher wäre meine Vermutung gewesen, dass diese Zeile UB ist. Kann mir auch schwerlich vorstellen, wie sie denn definiert sein sollte.

    (Wir sind uns einig, dass das ein Fehler ist. Ich kenne den C-Standard, insbesondere das genaue Wording hier, leider nicht so genau, daher die Frage, wie sich dieser Fehler nennt.)



  • @wob
    siehe auch meine eben ergänzten letzten Zeilen


Anmelden zum Antworten