2009-06-04 7 views
1

J'ai travaillé sur un projet open source pendant un certain temps, http://gtkworkbook.sourceforge.net/, et récemment rencontré un problème qui semble juste que je vais en rond. Je suis à peu près sûr qu'il y a un problème de tas, mais j'ai regardé ce code trop longtemps pour comprendre exactement ce que c'est. Donc, en bref, ce que je fais est de réallouer un bloc de mémoire à partir de pointeurs N vers des pointeurs M tout en travaillant avec un analyseur libcsv. S'il y a des colonnes supplémentaires, je veux augmenter la taille maximale du tableau à 2 fois la taille actuelle. Voici le code actuellement:Valgrind: Invaild lire de la taille 8


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); 
    } 

Voici la sortie valgrind:

 
==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) 

ligne sheet.c 351


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

La fonction de toute 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 fil analyseur


    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

Pouvez-vous le réduire un peu? Ce qui est sur la ligne 351 dans sheet.c. Il semble que vous lisez des données en mémoire que vous n'avez pas attribuées ou qui ont été désallouées. – Kekoa

+0

Ok, désolé, c'est ajouté. –

Répondre

2

Je suppose que vous exécutez dans une condition de course avec filetage. Cb1 réalloue le tableau pendant que votre analyseur tente de l'utiliser. Après le realloc, l'ancienne adresse n'est plus valide et c'est de là que provient votre lecture invalide. Vous aurez besoin de mettre un verrou (peut-être un verrou lecteur/graveur) autour du tableau pour éviter de rencontrer ce problème. Si c'est possible, essayez d'exécuter ce code à un seul thread pour voir si le problème se reproduit. Si ce n'est pas le cas, c'est un problème de threading, sinon c'est tout autre chose.

+0

C'était l'une de mes dernières pensées. Je vais tester cette avenue. –

+0

En fait, je ne suis pas sûr que ce soit le cas maintenant que je pense un peu plus. L'analyseur CSV et cb1 sont exécutés à partir du même thread; La méthode csv_parse de libcsv appelle cb1 (et cb2) après chaque colonne et chaque ligne sont analysées respectivement. L'appel à libworkbook (sheet_method_apply_cellarray) attend que le verrou de dessin GDK exécute quoi que ce soit. –

+0

J'ajoute le thread d'exécution où la méthode de l'analyseur est invoquée; la méthode cb1 est statique dans ce fichier. –

Questions connexes