2009-06-04 14 views
1

私はしばらくの間、オープンソースプロジェクトに取り組んでいましたが、最近はサークルに入っているような問題に直面しました。私はかなりヒープ問題があると確信していますが、私はこのコードを見て、それが何であるかを正確に把握しています。Valgrind:サイズの読み込み8

libsvパーサーを使って作業している間、簡単に言えば、私は、M個のポインタからN個のポインタまでメモリのブロックを再割り当てしています。追加の列がある場合、配列の最大サイズを現在のサイズの2倍に増やしたいと考えています。ここで


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

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) 

sheet.cライン351


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

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パーサスレッド


    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

少し絞ることができますか? sheet.cの351行目にあるもの。割り当てられていない、または割り当てが解除されているメモリ内のデータを読み込んでいるようです。 – Kekoa

+0

さて、申し訳ありませんが、それが添付されています。 –

答えて

2

私の推測では、あなたがスレッドとの競合状態に実行されていることです。パーザがそれを使用しようとしている間にCb1が配列を再割り当てしています。 reallocの後、古いアドレスはもはや有効でなくなり、無効な読み取りがどこから来るのかが分かります。この問題を回避するために、配列の周りにロック(たぶんリーダー/ライターロック)を置く必要があります。可能であれば、このコードをシングルスレッドで実行して、問題が再現するかどうか確認してください。そうでなければ、それはスレッドの問題です。そうでなければ、まったく別のものです。

+0

それは私の最新の考えの一つでした。私はこの道を試してみる。 –

+0

実際、私はこれがもう少しだと思うようになったのかどうかはわかりません。 CSVパーサーとcb1は同じスレッドから実行されています。 libcs​​vのcsv_parseメソッドは、それぞれの列と行がそれぞれ解析された後にcb1(およびcb2)を呼び出します。 libworkbook(sheet_method_apply_cellarray)の呼び出しは、何かを実行するためにGDKの描画ロックを待機します。 –

+0

私はパーサメソッドが呼び出される実行スレッドを追加しています。 cb1メソッドはこのファイルに対して静的です。 –

関連する問題