malloc() Fehler bei SQL Insert Befehl



  • Hallo,

    ich nochmal 😃

    Ich habe ein Programm geschrieben, dass jede 10 Sekunden drei Zufallswerte generiert und diese mit dem aktuellen Datum und der Uhrzeit in eine SQLite3 Datenbank abspeichert.

    Das Programm läuft soweit, jedoch wenn die Schleife vier mal durchgelaufen ist, erhalte ich folgende Fehlermeldung:

    *** Error in `./test': malloc(): memory corruption: 0x0000000002350d80
    Aborted (core dumped)

    Scheint wohl so, als ob das Programm seine Grenzen nicht kennt und gerne mal außerhalb des zugewiesenen Speichers arbeitet.

    Dieses Problem tritt nicht bei dem Schreiben in der Datenbank auf. Das Generieren von Zufallszahlen ist nicht der Grund für die Fehlermeldung.

    Das hier ist der Datenbank Code:

    static int callback(void *NotUsed, int argc, char **argv, char **azColName)
    {
        int i;
        for(i=0; i<argc; i++)
        {
            printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
        }
        printf("\n");
        return 0;
    }
    
    string quotesql( const string& s ) {
        return string("'") + s + string("'");
    }
    
    void messen::speichern(double p_id, double p_tempout, double p_tempin, double p_humidy,string p_time, string p_date)
    {
    
    // Übergabeparameter von messung() werden hier in die Datenbank abgespeichert
    
        sqlite3 *db;
        char *zErrMsg = 0;
        int rc;
    
        /* Double in String konvertieren */
        stringstream NumberString;
    
        NumberString << p_id;
        string stringpid = NumberString.str();
        NumberString.str("");
    
        NumberString << p_tempout;
        string stringptempout = NumberString.str();
        NumberString.str("");
    
        NumberString << p_tempin;
        string stringtempin = NumberString.str();
        NumberString.str("");
    
        NumberString << p_humidy;
        string stringphumidy = NumberString.str();
        NumberString.str("");
    
        string stringptime = p_time;
    
        string stringpdate = p_date;
    
        /* Open database */
        rc = sqlite3_open("wetterstation.db", &db);
        if( rc )
        {
            fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
            exit(0);
        }
        else
        {
            fprintf(stderr, "Opened database successfully\n");
        }
    
        string sqlstatement =
        "INSERT INTO messwerte (ID,tempout,tempin,humidy, time, date) VALUES ("
        + quotesql(stringpid) + ","
        + quotesql(stringptempout) + ","
        + quotesql(stringtempin) + ","
        + quotesql(stringphumidy) + ","
        + quotesql(stringptime) + ","
        + quotesql(stringpdate) + ");";
    
        /* Wandelt string sqlstatement in char um */
        char * buffer = new char[sqlstatement.length()];
        strcpy(buffer,sqlstatement.c_str());
    
        /* Execute SQL statement */
        rc = sqlite3_exec(db, buffer, callback, 0, &zErrMsg);
        if( rc != SQLITE_OK )
        {
            fprintf(stderr, "SQL error: %s\n", zErrMsg);
            sqlite3_free(zErrMsg);
        }
        else
        {
            fprintf(stdout, "Messwerte abgespeichert\n");
        }
        sqlite3_close(db);
    
    }
    

    Dies ist meine Schleife zum Aufrufen der speicher Funktion

    void messen::messung()
    {
        // Klasse die Messwerte ausliest und abspeichert
    
        double i = 1; // Variable für DB Schlüssel-ID
    
        while(1)
        {
            i=i;
            speichern(i, tempout(), tempin(), humidy(), zeit(), datum());
            i++;
            usleep( DELAY * 1000000 );
    
        }
    


  • /* Wandelt string sqlstatement in char um */
        // hier fehlt +1 für die 0 am Ende des strings
        char * buffer = new char[sqlstatement.length()];
        strcpy(buffer, sqlstatement.c_str());
    
        /* Execute SQL statement */
        rc = sqlite3_exec(db, buffer, callback, 0, &zErrMsg);
        // wieso nicht einfach
        rc = sqlite3_exec(db, sqlstatement.c_str(), callback, 0, &zErrMsg); //?
    
        // wenn schon new dann bitte auch
        delete [] buffer;
    


  • Super das hat geklappt!

    Kurze andere Frage.

    Ich möchte die messen::messung() bei Programmstart nebenbei laufen lassen.

    Ich habe mal sowas davon gehört, dass das mit pthread funktionieren soll.
    Welchen Befehl muss ich dazu benutzen?



  • Kurze Antwort: solange du noch nicht genug Erfahrung hast, solche Fehler selber zu finden, lässt du besser die Finger von Threads.



  • manni66 schrieb:

    Kurze Antwort: solange du noch nicht genug Erfahrung hast, solche Fehler selber zu finden, lässt du besser die Finger von Threads.

    Nun ja. Ich würde gerne, aber Sinn und Zweck des Programms soll sein,
    dass beim Starten eine Klasse dauerhaft parallel ausgeführt wird (eine Art Hintergrunddienst). Währenddessen kann man im eigentlichen Hauptprogramm normal die anderen Klasse nutzen.



  • Mit C++11 siehe http://en.cppreference.com/w/cpp/thread/thread/thread

    Aber ich habe dich gewarnt ...



  • [quote="julianpe"
    Das hier ist der Datenbank Code:

    /* Wandelt string sqlstatement in char um */
        char * buffer = new char[sqlstatement.length()];
        strcpy(buffer,sqlstatement.c_str());
    

    [/quote]Die Lösung kam hier ja schon. Hier die Erklärung, warum es vorher nicht funktioniert hat. strcpy kopiert den String inklusive Nullterminierung. Das bedeutet, dass der Puffer ein Byte länger sein muss als der String.

    Und noch was:

    julianpe schrieb:

    string quotesql( const string& s ) {
        return string("'") + s + string("'");
    }
    [code="cpp"]
    

    Das ist vielleicht die schlechteste quote-Funktion, die man sich vorstellen kann. Erst mal brauchst Du keine temporären Strings:

    return '\'' + s + '\'';
    

    Und überhaupt solltest Du strings wenn schon dann auch escapen. Was ist, wenn s ein Hochkomma enthält? Dann hast Du eine SQL-Injection. Man sollte bei Datenbanken immer die entsprechenden prepared statements mit Platzhaltern verwenden. Also bei sqlite sqlite_prepare_v2 und sqlite_bind_parameter_index . Das ist komplizierter und daher empfehle ich dringend, nicht die C-Schnittstelle zu verwenden sondern eine geeignete Datenbankbibliothek zu verwenden.


Anmelden zum Antworten