Verhalten von fcloseall und dessen Einsatzgebiet



  • The fread function reads, into the array pointed to by ptr, up to nmemb elements whose size is specified by size, from the stream pointed to by stream.

    Das selbe in grün für fwrite(), fclose() und andere. Die Funktionen (oder irgendwelche von ihnen aufgerufene) müssen den Pointer dereferenzieren ~> kabumm.



  • @RBS2 sagte in Umgangston:

    Was letztlich egal ist. Die Frage ist "Fehlercode oder Absturz". Husti sagt, das Programm nippelt ab.

    "debug assertion failed" unter visual studio bzw. mit debug informationen, "project1.exe funktioniert nicht mehr" wenn als "release" compiliert nach _fcloseall. gleiches verhalten, wenn die datei schreibgeschützt ist (logisch, NULL). stimmt also!

    wie das jetzt mit dem vollen laufwerk ist, weiß ich nicht, aber wahrscheinlich schlägt fwrite dann fehl und du kannst ferror auswerten.



  • @Wade1234 sagte in Verhalten von fcloseall und dessen Einsatzgebiet:

    @RBS2 sagte in Umgangston:

    Was letztlich egal ist. Die Frage ist "Fehlercode oder Absturz". Husti sagt, das Programm nippelt ab.

    "debug assertion failed" unter visual studio bzw. mit debug informationen, "project1.exe funktioniert nicht mehr" wenn als "release" compiliert nach _fcloseall. gleiches verhalten, wenn die datei schreibgeschützt ist (logisch, NULL). stimmt also!

    wie das jetzt mit dem vollen laufwerk ist, weiß ich nicht, aber wahrscheinlich schlägt fwrite dann fehl und du kannst ferror auswerten.

    Nein, nicht gleiches Verhalten.

    Im "schreibgeschützt" Fall bekommt man einfach einen NULL Zeiger zurück. Das kann man prüfen. Wenn man es nicht prüft ist das ein Fehler den man selbst gemacht hat, im eigenen Code, der eigenen Komponente.

    Im "no space left on device" Fall bekommt man einen gültigen, funktionierenden, non-NULL FILE*. Wenn man dann versucht etwas damit zu schreiben bekommt man einfach einen Fehlercode von der Schreibfunktion zurück. Kann man ebenso behandeln, wenn man es nicht macht ist man ebenso selbst schuld, eigener Code, eigene Komponente.

    Im _fcloseall Fall dagegen bekommt man auch erstmal einen gültigen, funktionierenden, non-NULL FILE*. Und alles funktioniert erstmal wunderbar. Bis zu dem Zeitpunkt wo z.B. eine andere Komponente, evtl. sogar in einem anderen Thread, _fcloseall aufruft. Und ab dem Moment kracht es dann* wenn man versucht den FILE* nochmal zu verwenden. Der FILE* den man irgendwo in einer Variable gespeichert hat wird dadurch aber nicht NULL, er wird bloss ungültig, "dangling" halt. Grosses Problem, und nicht selbst verursacht. Nicht im eigenen Code, nicht in der eigenen Komponente.

    Also ganz ganz grosser Unterschied. Fall 1 und 2 kann man problemlos behandeln und sollte IMO auch jedes brauchbare Programm behandeln. Fall 3 kann man theoretisch in kleinen, 100% selbstgeschriebenen Programmen (=keine thirdparty Libraries etc.) kontrolliert behandeln, aber mMn. nur wenn man total bekloppte Einschränkungen akzeptiert. Praktisch, in realen, grösser als winzigen Projekten ist Fall 3 aber ein verdammtes riesen Problem. Ca. so gross wie andere fremden Speicher zu überschreiben oder alles grundsätzlich und überall über globale Variablen zu machen ("wer braucht schon Parameter?").


    *: Oft, aber natürlich nicht garantiert. Es kann quasi fast alles passieren, z.B. dass man ins falsche File schreibt und es nicht mal merkt. Oder State einer dritten Komponente zerschiesst ohne dass gleich etwas abstürzt. Undefiniert halt. Schlecht.


    ps: Mir fällt gerade auf, du könntest "gleiches Verhalten" auch auf dein Testprogramm bezogen haben, wo du der Einfachkeit halber den NULL Check weggelassen hast. In dem Fall ja, klar, vermutlich gleiches Verhalten. Nur halt nicht gleiches Problem in realer Software, da 1x problemlos behandelbar und 1x totale Katastrophe.



  • @RBS2 sagte in Verhalten von fcloseall und dessen Einsatzgebiet:

    @Wade1234 sagte in Umgangston:

    witzig, dass wir hier in einem thread, der davon handelt, dass der umgangston schlecht ist, irgendwas ausdiskutieren und der umgangston dabei schlecht ist.

    Was lernen wir daraus? Also trotz allen Gepöbels immer cool bleiben. Guter Thread! 🔝

    Oder auch dass man ruhig erstmal nachfragen kann, wenn...

    • jemand irgendwo sagt "X hat in sauberer Software nix verloren" und
    • man irgendwie nicht so ganz versteht warum/das nicht so sieht und
    • man nicht so genau weiss was X eigentlich ist/tut

    ...bevor man anfängt ihn darüber zu belehren dass man das auch anders sehen kann.



  • @hustbaer sagte in Verhalten von fcloseall und dessen Einsatzgebiet:

    ps: Mir fällt gerade auf, du könntest "gleiches Verhalten" auch auf dein Testprogramm bezogen haben, wo du der Einfachkeit halber den NULL Check weggelassen hast. In dem Fall ja, klar, vermutlich gleiches Verhalten. Nur halt nicht gleiches Problem in realer Software, da 1x problemlos behandelbar und 1x totale Katastrophe.

    ja das war auch auf mein (windows-) testprogramm bezogen.

    unter freebsd stürzt da übrigens nichtmal was ab, das programm läuft ganz normal. die schreiboperation nach log.txt erfolgt, weil der stdout ja geschlossen ist. edit: moment, da stimmt irgendwas mit der ausgabe nicht. ich erhalte n == 5 und errno 9 (ungültige datei). bug im compiler?

    #include <unistd.h>
    #include <fcntl.h>
    #include <errno.h>
    
    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
            int file;
            int n;
            char str[100];
            char str1[100];
            char str2[100];
    
            file = open("test.txt", O_RDWR | O_CREAT);
            if(file == -1)
            {
                    printf("open failed\n");
                    return 1;
            }
    
            fcloseall();
            //close(file);
    
            n = write(file, "test", 5);
            close(file);
    
            file = open("log.txt", O_WRONLY);
    
            sprintf(str1, "%d bytes written.\n", n);
            write(file, str1, strlen(str1) + 1);
    
            if(n <= 0)
            {
                    sprintf(str2, "errno: %d\n", errno);
                    write(file, str2, strlen(str2) + 1);
            }
    
            close(file);
    
    
            return 0;
    }
    
    


  • @Wade1234 sagte in Verhalten von fcloseall und dessen Einsatzgebiet:

    unter freebsd stürzt da übrigens nichtmal was ab, das programm läuft ganz normal. die schreiboperation nach log.txt erfolgt, weil der stdout ja geschlossen ist. edit: moment, da stimmt irgendwas mit der ausgabe nicht. ich erhalte n == 5 und errno 9 (ungültige datei). bug im compiler?

    Das könnte damit zu tun haben dass undefiniertes Verhalten undefiniertes Verhalten ist.



  • undefiniertes verhalten bedeutet doch, dass man die bedienungsanleitung des compilers lesen soll, oder nicht?



  • @Wade1234
    Nö, undefiniertes Verhalten bedeutet, dass das Programm machen darf, was es will, und der Compiler trotzdem alles richtig gemacht hat. Nur halt der Programmierer nicht.


  • Administrator

    @Wade1234 sagte in Verhalten von fcloseall und dessen Einsatzgebiet:

    undefiniertes verhalten bedeutet doch, dass man die bedienungsanleitung des compilers lesen soll, oder nicht?

    Ist das als Witz gemeint? Falls nicht: Geh bei undefiniertem Verhalten davon aus, dass theoretisch dein Programm die Welt explodieren lässt. Es ist undefiniert, es kann alles passieren. Der Compiler definiert da nichts, er nimmt schlicht keine Rücksicht. Sonst wäre es Implementations spezifisches Verhalten.



  • und ihr könnt da keinen "designfehler" oder so entdecken?





  • @Wade1234 sagte in Verhalten von fcloseall und dessen Einsatzgebiet:

    und ihr könnt da keinen "designfehler" oder so entdecken?

    Nein. Wenn du's kuschelig warm und immer (*) definiert haben willst, dann musst du ne "managed" Sprache ala Java oder C# verwenden. Wenn dich das jetzt überrascht, dann könnte vielleicht ein Bisschen Backgroundwissen nicht schaden. Also darüber wie Computer allgemein so funktionieren (CPU, RAM, Registert), wie Speicherverwaltung typischerweise gemacht wird und wie das so mit den Zeigern ist.

    *: Naja, ne, leider doch nicht immer. Aber eher/öfter als bei C++.



  • naja also ich weiß, dass ich ungültige zeiger auf NULL setzen soll, damit das programm, wenn ich diesen zeiger fehlerhafterweise verwende, gesichert abstürzt und nicht mit falschen werten weiter läuft, und wahrscheinlich sollte man das mit dateideskriptoren auch so machen.


  • Gesperrt

    Habs auch mal (mit VS) getestet. fwrite() reagiert tatsächlich allergisch auf einen geschlossenen FILE*.

    Aber mit einen kleinen Trick lässt sich das umgehen:

    
    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    	FILE *f1 = fopen("c:\\f1", "w");
    	FILE *f2 = fopen("c:\\f2", "w");
    	printf("%d\n", _fileno(f1));  // positive zahl
    	printf("%d\n", _fileno(f2));  //  "       "
    	_fcloseall();
    	printf("%d\n", _fileno(f1));  // -1
    	printf("%d\n", _fileno(f2));  // dito
    }
    

    Also vor dem Zugriff immer mit _fileno() auf Gültigkeit des FILE* checken, dann klappt's auch mit _fcloseall().

    Btw, Nach einem gezielten fclose() spuckt _fileno() auch -1 aus. 🐱


  • Administrator

    @RBS2 Hmmmm

    https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fileno?view=vs-2017

    The result is undefined if stream does not specify an open file.


  • Gesperrt

    @Dravere sagte in Verhalten von fcloseall und dessen Einsatzgebiet:

    @RBS2 Hmmmm

    https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fileno?view=vs-2017

    The result is undefined if stream does not specify an open file.

    Da wollte MS wohl wieder etwas anders machen.

    Upon successful completion, fileno() shall return the integer value of the file descriptor associated with stream. Otherwise, the value -1 shall be returned and errno set to indicate the error.

    http://pubs.opengroup.org/onlinepubs/009696899/functions/fileno.html



  • @RBS2
    Ich finde das inzwischen bewundernswert, mit welcher Ignoranz und Hartnäckigkeit du deinen Standpunkt verteidigst. Hat irgendwie so´n Flachweltler-Charme. Witzig anzuhören, aber nicht ernst zu nehmen.


  • Gesperrt

    @DocShoe sagte in Verhalten von fcloseall und dessen Einsatzgebiet:

    Hat irgendwie so´n Flachweltler-Charme.

    Dass die Erde eine Scheibe ist, weiß doch inzwischen jeder auf dem gesamten Globus. 😆


Anmelden zum Antworten