2009-06-04 8 views
1

Ich habe an einem Open-Source-Projekt für eine Weile, http://gtkworkbook.sourceforge.net/ gearbeitet, und vor kurzem lief ein Problem, das gerade scheint, als ob ich im Kreis gehe. Ich bin mir ziemlich sicher, dass es ein Heap-Problem gibt, aber ich habe diesen Code zu lange untersucht, um genau herauszufinden, was es ist.Valgrind: Invaild lesen Größe 8

Also, was ich gerade mache, ist ein Speicherblock von N-Zeigern zu M Zeigern während der Arbeit mit einem libcsv-Parser neu zuzuweisen. Wenn es zusätzliche Spalten gibt, möchte ich die maximale Größe des Arrays auf das 2-fache der aktuellen Größe erhöhen. Hier ist der Code zur Zeit:


struct csv_column { 
    Sheet * sheet; 
    Cell ** array; 
    int & array_max; 
    int & array_size; 
    int row; 
    int field; 
    char * value; 
    }; 

    static void 
    cb1 (void * s, size_t length, void * data) { 
    struct csv_column * column = (struct csv_column *) data; 
    int & array_max = column->array_max; 

    // Resize the cell array here. 
    if (column->field >= array_max) { 
     int max = (2 * array_max); 
     (column->array) = (Cell **) g_realloc ((column->array), max * sizeof (Cell*)); 

     for (int ii = array_max; ii array)[column->field] == NULL) 
     (column->array)[column->field] = cell_new(); 

    Cell * cell = (column->array)[column->field]; 
    cell->set_row (cell, column->row); 
    cell->set_column (cell, column->field++); 
    cell->set_value_length (cell, s, length); 
    } 

    CsvParser::CsvParser (Workbook * wb, 
      FILE * log, 
      int verbosity, 
      int maxOfFields) { 
    this->wb = wb; 
    this->log = log; 
    this->verbosity = verbosity; 
    this->sizeOfFields = 0; 
    this->maxOfFields = maxOfFields; 
    this->fields = (Cell **) g_malloc (maxOfFields * sizeof (Cell*)); 

    for (int ii = 0; ii maxOfFields; ii++) 
     this->fields[ii] = NULL; 
    } 

    CsvParser::~CsvParser (void) { 
    for (int ii = 0; ii maxOfFields; ii++) { 
     if (this->fields[ii]) 
     this->fields[ii]->destroy (this->fields[ii]); 
    } 

    g_free (this->fields); 
    } 

Hier wird der valgrind Ausgang:

 
==28476== Thread 9: 
==28476== Invalid read of size 8 
==28476== at 0x771AF4F: sheet_method_apply_cellarray (sheet.c:351) 
==28476== by 0xD930DB7: largefile::CsvParser::run(void*) (CsvParser.cpp:147) 
==28476== by 0xDD624C8: concurrent::thread_run(void*) (Thread.cpp:28) 
==28476== by 0xA7B73B9: start_thread (in /lib/libpthread-2.9.so) 
==28476== by 0x80DBFCC: clone (in /lib/libc-2.9.so) 
==28476== Address 0xbc5d4a8 is 0 bytes inside the accessing pointer's 
==28476== once-legitimate range, a block of size 160 free'd 
==28476== at 0x4C25D4F: free (vg_replace_malloc.c:323) 
==28476== by 0xD9314CA: largefile::cb1(void*, unsigned long, void*) (CsvParser.cpp:57) 
==28476== by 0xDB42681: csv_parse (in /home/jbellone/work/gtkworkbook/lib/libcsv.so) 
==28476== by 0xD930D00: largefile::CsvParser::run(void*) (CsvParser.cpp:136) 
==28476== by 0xDD624C8: concurrent::thread_run(void*) (Thread.cpp:28) 
==28476== by 0xA7B73B9: start_thread (in /lib/libpthread-2.9.so) 
==28476== by 0x80DBFCC: clone (in /lib/libc-2.9.so) 
==28476== 
==28476== Invalid read of size 8 
==28476== at 0x771AF66: sheet_method_apply_cellarray (sheet.c:351) 
==28476== by 0xD930DB7: largefile::CsvParser::run(void*) (CsvParser.cpp:147) 
==28476== by 0xDD624C8: concurrent::thread_run(void*) (Thread.cpp:28) 
==28476== by 0xA7B73B9: start_thread (in /lib/libpthread-2.9.so) 
==28476== by 0x80DBFCC: clone (in /lib/libc-2.9.so) 
==28476== Address 0xbc5d4a8 is 0 bytes inside the accessing pointer's 
==28476== once-legitimate range, a block of size 160 free'd 
==28476== at 0x4C25D4F: free (vg_replace_malloc.c:323) 
==28476== by 0xD9314CA: largefile::cb1(void*, unsigned long, void*) (CsvParser.cpp:57) 
==28476== by 0xDB42681: csv_parse (in /home/jbellone/work/gtkworkbook/lib/libcsv.so) 
==28476== by 0xD930D00: largefile::CsvParser::run(void*) (CsvParser.cpp:136) 
==28476== by 0xDD624C8: concurrent::thread_run(void*) (Thread.cpp:28) 
==28476== by 0xA7B73B9: start_thread (in /lib/libpthread-2.9.so) 
==28476== by 0x80DBFCC: clone (in /lib/libc-2.9.so) 

sheet.c Linie 351


    gtk_sheet_set_cell_text (GTK_SHEET (sheet->gtk_sheet), 
       array[ii]->row, 
       array[ii]->column, 
       array[ii]->value->str); 

Die ganze Funktion von sheet.c:


static void 
sheet_method_apply_cellarray (Sheet * sheet, 
        Cell ** array, 
        gint size) 
{ 
    ASSERT (sheet != NULL); 
    g_return_if_fail (array != NULL); 

    gdk_threads_enter(); 

    /* We'll see how this performs for now. In the future we may want to go 
    directly into the GtkSheet structures to get a little more performance 
    boost (mainly because we should not have to check all the bounds each 
    time we want to update). */ 
    for (gint ii = 0; ii gtk_sheet), 
       array[ii]->row, 
       array[ii]->column, 
       array[ii]->value->str); 

    if (!IS_NULLSTR (array[ii]->attributes.bgcolor->str)) 
     sheet->range_set_background (sheet, 
        &array[ii]->range, 
        array[ii]->attributes.bgcolor->str); 

    if (!IS_NULLSTR (array[ii]->attributes.fgcolor->str)) 
     sheet->range_set_foreground (sheet, 
        &array[ii]->range, 
        array[ii]->attributes.fgcolor->str); 

    /* Clear all of the strings */ 
    g_string_assign (array[ii]->value, ""); 
    g_string_assign (array[ii]->attributes.bgcolor, ""); 
    g_string_assign (array[ii]->attributes.fgcolor, ""); 
    } 

    gdk_threads_leave(); 
} 

CSV-Parser-Thread


    void * 
    CsvParser::run (void * null) { 
    this->running = true; 
    std::queue queue; 
    struct csv_parser csv; 
    struct csv_column column = {this->wb->sheet_first, 
       this->fields, 
       this->maxOfFields, 
       this->sizeOfFields, 
       0, 
       0, 
       new char [1024]}; 

    if (csv_init (&csv, CSV_STRICT) != 0) { 
     std::cerr running == true) { 
     if (this->inputQueue.size() > 0) { 

    // Lock, copy, clear, unlock. - Free this up. 
    this->inputQueue.lock(); 
    this->inputQueue.copy (queue); 
    this->inputQueue.clear(); 
    this->inputQueue.unlock(); 

    while (queue.size() > 0) { 
     std::string buf = queue.front(); queue.pop(); 
     size_t bytes = buf.length(); 

     if (this->running == false) 
     break; 

     if ((bytes = csv_parse (&csv, buf.c_str(), bytes, cb1, cb2, &column)) == bytes) { 
     if (csv_error (&csv) == CSV_EPARSE) { 
      std::cerr wb->sheet_first->apply_array (this->wb->sheet_first, 
              this->fields, 
              this->sizeOfFields); 

     if (column.row >= (column.sheet)->max_rows) 
     column.row = 0; 
    } 
     } 
     concurrent::Thread::sleep(1); 
    } 

    return NULL; 
    } 
+0

Können Sie es ein wenig eingrenzen? Was ist in Zeile 351 in Blatt.c. Es klingt, als würden Sie Daten im Speicher lesen, die Sie nicht zugewiesen haben oder deren Zuordnung aufgehoben wurde. – Kekoa

+0

Okay, tut mir leid, es ist angehängt. –

Antwort

2

Meine Vermutung ist, dass Sie mit einem Gewinde in eine Race-Bedingung ausgeführt werden. Cb1 ordnet das Array neu zu, während der Parser versucht, es zu verwenden. Nach dem Realloc ist die alte Adresse nicht mehr gültig und hier kommt Ihre ungültige Adresse. Sie müssen eine Sperre (möglicherweise eine Lese-/Schreibsperre) um das Array setzen, um dieses Problem nicht zu lösen. Wenn es möglich ist, versuchen Sie, diesen Code single-threaded auszuführen, um zu sehen, ob das Problem reproduziert. Wenn es das nicht tut, ist es ein Threading-Problem, ansonsten ist es etwas ganz anderes.

+0

Das war einer meiner letzten Gedanken. Ich werde diese Avenue testen. –

+0

Eigentlich bin ich mir nicht sicher, ob das jetzt der Fall ist, denke ich ein wenig mehr. Der CSV-Parser und cb1 werden vom selben Thread ausgeführt; Die csv_parse-Methode von libcsv ruft cb1 (und cb2) auf, nachdem jede Spalte und Zeile analysiert wurde. Der Aufruf von libworkbook (sheet_method_apply_cellarray) wartet auf die GDK-Zeichnungssperre, um irgendetwas auszuführen. –

+0

Ich füge den Ausführungsthread hinzu, wo die Parser-Methode aufgerufen wird; Die cb1-Methode ist für diese Datei statisch. –

Verwandte Themen