Speicherüberlauf beim einlesen einer CSV-Datei



  • Hallo,

    ich habe mir eine Funktion geschrieben um eine CSV-Datei zu lesen.
    Die CSV-Datei hat insgesamt 70 Zeilen, jedoch steht in der 70 Zeile nur 0x0A laut Hexeditor.
    Mein Problem ist nun ich bekomme einen Speicherüberlauf.

    Ich kann das Problem mit Debugger nachvollziehen, jedoch kann ich es mir nicht erklären.
    Die letzte funktionierende Zeile heißt:
    M2;12;rrm_start;112347881
    funktioniert soweit so gut.
    Wenn "fgets" zum letzten mal aufgerufen wird, steht in der Variable buffer
    ";112347881"
    Das kann ich mir überhaupt nicht erklären.

    int lese_file(char *filename)
    {
    FILE *fp;
    char buffer[256];
    char *adbuff;
    int i=0;
    
    	if ((fp = fopen(filename, "r")) == NULL)
    	{
    	/* ERROR */ ;
    		printf ("CSV-Datei konnte zum lesen nicht geoeffnet werden");
    		exit (-1);
    	}
    
    	while (fgets(buffer, sizeof(buffer), fp))
    	{
    
    /* lösche alle Leerzeichen */
    		delblanks(buffer,false);
    
    		if (buffer[0] == '#' || buffer[0] == ';'|| strlen(buffer) <= 1) continue;   /*Kommentar herausfiltern */
    
    		adbuff = strtok(buffer,";");
    		if (adbuff == NULL)
    		{
    			printf ("konnte Anlagenname in CSV-Datei nicht finden\nZeile:%i",i);
    			return -1;
    		}
    
    		strcpy(paramzeile[i].anlage,adbuff);
    
    		paramzeile[i].mpi = atoi(strtok(NULL,";"));
    
    		adbuff = strtok(NULL,";");
    		if (adbuff == NULL)
    		{
    			printf ("konnte Variablenname in CSV-Datei nicht finden\nZeile:%i",i);
    			return -1;
    		}
    
    		strcpy(paramzeile[i].varname,adbuff);
    
    		paramzeile[i].wert = atoi(strtok(NULL,";"));
    		i++;
    	}
    	fclose(fp);
    

    Ich könnte natürlich die letzte Zeile löschen und das Problem ist weg, jedoch kann so eine CSV-Datei immer vorkommen und dann stürzt mein Programm ab.
    Übrigens in Zeile 31 ist der Speicherüberlauf.... ist klar

    Danke



  • Hi,

    habs nur überflogen, aber ich sehe an keiner Stelle die Speicherreservierung für adbuff.



  • Scheint auch nicht nötig zu sein.

    cplusplus.com schrieb:

    strtok
    Syntax:
    #include <string.h>
    char *strtok( char *str1, const char *str2 );

    The strtok() function returns a pointer to the next "token" in str1, where str2 contains the delimiters that determine the token. strtok() returns NULL if no token is found. In order to convert a string to tokens, the first call to strtok() should have str1 point to the string to be tokenized. All calls after this should have str1 be NULL.
    For example:

    char str[] = "now # is the time for all # good men to come to the # aid of their country";
       char delims[] = "#";
       char *result = NULL;
       result = strtok( str, delims );
       while( result != NULL ) {
           printf( "result is /"%s/"/n", result );
           result = strtok( NULL, delims );
       }
    

    The above code will display the following output:
    result is "now "
    result is " is the time for all "
    result is " good men to come to the "
    result is " aid of their country"



  • du hast einen fixen puffer von 256 byte. in diesen puffer liest du immer eine zeile ein. ist die zeile kleiner als 256 zeichen klappt das, ist sie aber größer, hast du nur den ersten teil der zeile im puffer. beim nächsten fgets bekommst du dann den rest der zeile (oder wieder nur einen teil, sollte die zeile um ein vielfaches länger als 256 byte sein.) schau dir mal getline bzw. getdelim an. das sind aber leider beides gnu extensions und nur in der glibc mit sicherheit verfügbar.
    der zu kleien puffer könnte das problem sein, wieso du dann nur mehr
    ";112347881" in buffer stehen hast.

    worst_case schrieb:

    strcpy(paramzeile[i].anlage,adbuff);
    

    hier prüfst du nicht, ob der puffer (oder was auch immer paramzeile[i].anlage ist...) groß genug ist, um den ganzen string aufzunehmen, auf den adbuff zeigt. strncpy mit der größe von paramzeile[i].anlage kannst du hier verwenden oder du prüfst mit strlen(adbuff) vorher die länge von adbuff.



  • Hallo,

    und danke für eure Hilfe.
    Leider funktioniert es immer noch nicht.
    Ich teste derzeit die Stringlänge des buffer.
    Der hat aber max. 39 Zeichen pro Zeile belegt.

    Das abfragen der Länge vor dem kopieren ist sicher sinnvoll, jedoch nicht das Problem.
    Die buffer länge habe ich einfach mal auf 1024 (1k) gesetzt, immer das gleiche Problem. Auch die länge der Variablen "paramzeile[i].x" sind lang genug. (mehr als das 3 fache)

    Es dürfte überhaupt nicht sein, das eine Zeile (auch nur teilweise) wenn die bufferlänge groß genug ist, zwei mal im buffer auftaucht.
    Welchen Grund kann es dafür geben ??
    Ich möchte aber nicht von der Standard Library abweichen... nur wenn es unbedingt sein muss.:D

    Danke



  • wie groß ist denn das array "paramzeile"? hier prüfst du nicht, ob du überhaupt mit i noch auf ein gültiges element zugreifen kannst. sorry, hab das das beim ersten posting übersehen.



  • Hallo,

    die variablen paramzeile.x sind alle groß genug.
    Ich baue alles um und werde versuchen mit fscanf einzulesen.

    Danke


Anmelden zum Antworten