Очень странная ошибка malloc - PullRequest
1 голос
/ 17 января 2010

Хорошо. Итак, у меня есть эта функция, init ():

void init()
{
fstream file;
int index = 0;

char temp_list[60000][15];

listlen = 0;
current_index = 0;

file.open("en_US.dic");
while(!file.eof())
{   
    file >> temp_list[index];
    index++;
}

listlen = index;
file.close();
file.open("en_US.dic");

word_list = new char*[listlen];

int count = 0;
for(int i = 0; i < listlen; i++)
{
    word_list[i] = new char[21];
    file >> word_list[i];
}

file.close();
}

Этот код компилируется и работает правильно, без ошибок. Однако, когда я меняю строку

word_list[i] = new char[21]

до

word_list[i] = new char[x] //x < 21

Я получаю следующую ошибку:

dict: malloc.c:3074: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.

Я немного новичок в программировании (<2 года), и я никогда не видел ничего подобного. У кого-нибудь есть идеи? Заранее спасибо! </p>

Ответы [ 5 ]

5 голосов
/ 17 января 2010

Существует три основных проблемы с этим кодом, две из них здесь:

while (!file.eof())
{   
    file >> temp_list[index];
    index++;
}

Вы не можете проверить file.eof(), чтобы увидеть, если операция next не будет выполнена, только если previous нажмет eof, и это обычно полезно только в случае неудачи, поэтому измените ее на :

while (file >> temp_list[index]) {
    index++;
}

Поскольку извлечения (>>) возвращают поток, и поток можно тестировать напрямую, этот код теперь проверяет поток на каждой итерации и увеличивает индекс только в случае успешного извлечения.

Теперь при извлечении в массив символов входные потоки останавливаются на пробелах, но они не знают, какую максимальную длину они могут хранить, пока вы им не скажете. Эта же ошибка позже в коде, вероятно, объясняет то, что вы делаете, потому что я подозреваю, что вы читаете гораздо больше данных, чем ожидаете, и таким образом растоптываете всю свою память. Исправлено:

while (file >> std::setw(15) >> temp_list[index]) {
    index++;
}

Тем не менее, последняя серьезная проблема заключается в том, что вы выделяете ресурсы и пропускаете их, поэтому вместо них используйте vector и string:

#include <fstream>
#include <iostream>
#include <string>
#include <vector>

void init() {
  typedef std::vector<std::string> C; // for later convenience
  C words;
  {
    ifstream file ("en_US.dic");
    if (!file) {
      std::cerr << "could not open file\n";
      // handle error: throw an exception, call abort(), etc.
    }
    for (std::string word; file >> word;) {
      words.push_back(word);
    }
    // if you want to read lines instead:
    //for (std::string line; std::getline(file, line);) {
    //  words.push_back(line);
    //}
  }
  // now use words[0] through words[words.size() - 1]
  std::cout << "Read " << words.size() << " words:\n";
  for (int i = 0; i < words.size(); ++i) {
    std::cout << "  " << words[i] << '\n';
  }
  std::cout << "Output again:\n";
  for (C::const_iterator i = words.begin(); i != words.end(); ++i)
  {
    std::cout << "  " << *i << '\n';
  }
}
4 голосов
/ 17 января 2010

Я предполагаю, что одно из ваших слов длиннее значения, указанного в x.

Когда это произойдет, вы будете переполнять свой буфер malloc.

Если вы выделяете N байтов, вам нужно убедиться, что вы пишете не более N байтов.

Использование оператора >> и символьных буферов - путь к катастрофе. оператор >> будет продолжать чтение / запись, пока не достигнет разделителя слов. Так как operator >> не знает, насколько большой буфер char *, он переполнит буфер, когда слово длиннее, чем буфер. Если вы хотите использовать оператор >> для извлечения слов, используйте std :: string.

Что происходит

Очень распространенный способ реализации malloc - хранить данные учета между буферами, возвращаемыми из malloc. Когда вы перезаписываете эти данные, предположения, сделанные malloc относительно структуры данных, больше не существуют.

Итак, у malloc что-то вроде этого:

+------------------+-------------+------------------+-------------+-----------
| malloc internals | user buffer | malloc internals | user buffer | etc...
+------------------+-------------+------------------+-------------+-----------

Итак, если вы выделили 8 байтов в пользовательский буфер, а затем записали 12 байтов, вы просто уничтожили первые 4 байта следующей внутренней записи malloc.

1 голос
/ 17 января 2010

Если в файле есть слова длиной 20 или более, file >> word_list[i] запишет после конца выделенного буфера, что может привести к появившейся ошибке. Это называется переполнением буфера .

Это также проблема при записи в temp_list, но в этом случае переполнение буфера менее разрушительно, поскольку, вероятно, просто перезапишет память, используемую для следующего слова.

Одним из способов решения этой проблемы является использование массива std::string вместо char * - таким образом распределение будет выполняться автоматически.

0 голосов
/ 17 января 2010

Это действительно испортит:

for(int i = 0; i < listlen; i++)
{
    word_list[i] = new char[21];
    file >> word_list[i];
}

Если любое из слов больше 20 символов (+1 для '\ 0'). Тогда, в основном, вы будете писать о памяти, используемой менеджером памяти. Это вызовет всевозможные проблемы с последующим выделением и отменой выделения.

Это работало в предыдущем цикле, потому что буфер был смежным:

char temp_list[60000][15];

Хотя слово из одной строки могло перекрываться на следующей строке, это не было бы проблемой, если бы вы фактически не читали большое слово в temp_list [59999] (который перекрывался бы с другой переменной).

0 голосов
/ 17 января 2010

Вы можете изменить свой дизайн здесь. Словари огромные.
Вам нужно , чтобы перенести все слова (данные) в память?

Поскольку словари огромны, они спроектированы таким образом, что им не нужно одновременно быть полностью в памяти. Профессиональные словари имеют индексные таблицы, которые меньше, чем весь файл данных. Основная идея заключается в том, что индексные таблицы малы и могут быть перенесены в память и сохранены в памяти, а не перемещаться по всем данным одновременно.

Я оптимизировал программу, сохранив начальную индексную таблицу в памяти. Результатом первой индексной таблицы является смещение файла к другой таблице (или имя другого файла). Эта дополнительная таблица будет перетаскиваться в память, если это необходимо, и так далее, пока не будет найден точный элемент.

См. Следующие темы (поиск в Интернете):

  • B + Дерево
  • Индексные таблицы
  • Блок ввода / вывода
  • Смещение файла
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...