Pregunta

He estado trabajando en un proyecto de código abierto por un tiempo, http://gtkworkbook.sourceforge.net/, y recientemente se encontró con un problema que sólo parece que voy en círculos. Estoy bastante seguro de que hay un problema montón pero he estado buscando en el código demasiado tiempo para averiguar exactamente lo que es.

Así que, en resumen, lo que estoy haciendo es la reasignación de un bloque de memoria a partir de N punteros a punteros M mientras se trabaja con un analizador libcsv. Si hay columnas adicionales Quiero aumentar el tamaño máximo de la matriz a 2 veces el tamaño actual. Aquí está el código actualmente:


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

Aquí está la salida 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)

línea sheet.c 351


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

La función de toda 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 hilo analizador


  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;
  }
¿Fue útil?

Solución

Mi conjetura es que se está ejecutando en una condición de carrera con rosca. CB1 está reasignando la matriz, mientras que su analizador está tratando de usarlo. Después de la realloc la antigua dirección ya no es válida y que es donde su lectura no válida está viniendo. Tendrá que poner un candado (tal vez un lector / escritor de bloqueo) en torno a la matriz para evitar golpear a este problema. Si es posible, intente ejecutar el código de una sola rosca para ver si el problema se reproduce. Si no es así, entonces es un problema de roscado, de lo contrario es algo completamente distinto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top