Ошибка Маллока:неверная контрольная сумма для освобожденного объекта
Вопрос
Я работаю над реализацией хвоста для задания.У меня он работает правильно, однако я, кажется, получаю сообщение об ошибке в случайное время.
Я не вижу, чтобы отследить это как закономерность или что-то еще, кроме того, что это соответствует.
Например, если я назову свою программу «tail -24 test.in», я получу ошибку неправильной контрольной суммы в одной и той же строке при нескольких запусках.Однако с разными файлами и даже с разным количеством строк для печати я вернусь без ошибок.
Есть идеи, как отследить проблему, я часами пытался ее отладить, но безрезультатно.
Вот код нарушения:
линии определены как char** и были распределены по принципу malloc:
lines = (char**) malloc(nlines * sizeof(char *));
void insert_line(char *s, int len){
printf("\t\tLine Number: %d Putting a %d line into slot: %d\n",processed,len,slot);
if(processed > numlines -1){//clean up
free(*(lines+slot));
*(lines + slot) = NULL;
}
*(lines + slot) = (char *) malloc(len * sizeof(char));
if(*(lines + slot) == NULL) exit(EXIT_FAILURE);
strcpy(*(lines+slot),s);
slot = ++processed % numlines;
}
Решение
Ваша процедура пишет за пределами выделенного буфера строки.
Размер строки, передаваемой в качестве аргумента (то есть "len"), вероятно, не включает терминатор NUL. Когда вы вызываете malloc для копирования строки (то есть " s "), вам нужно выделить дополнительный байт для ограничителя строки:
*(lines + slot) = (char *) malloc((len + 1) * sizeof(char));
Другие советы
Если вы можете последовательно воспроизвести проблему с определенными входными параметрами, вам следует выполнить отладку следующим образом:
- Сначала выполните отладку до той бесплатной версии, которая вызывает проблему.
- Затем выясните, когда память, которая должна была быть освобождена, была выделена.
- Затем выполните отладку до места, где выделена память.
- Найдите в средстве просмотра памяти выделенный блок памяти.Обратите внимание на начало и конец блока.Вероятно, существует специальное значение, называемое охранный блок непосредственно перед и сразу после блока.
- Теперь выполните код, пока память не освободится.В какой-то момент ваш код должен по ошибке перезаписать защитный блок. Это оскорбительное заявление.
Обратите внимание, что проблема вполне может быть в совершенно другой части вашей программы.Несмотря на то, что именно этот файл сообщает об ошибке, код, который перезаписывает защитный блок, может находиться где угодно.
Мой первый вопрос: как рассчитать len? Это просто strlen или в нем есть место для терминатора \ 0? Я думаю, что вы, возможно, превышаете свое распределение в своей strcpy. Плохое поведение, как правило, происходит на границах слов и выглядит случайным. Кроме того, убедитесь, что исходные строки имеют нулевое завершение. Если вы допустили ошибку на стороне чтения и не прекратили их. Тогда strcpy может случайным образом перезаписывать вещи. Р>
*(lines + slot) = (char *) malloc(len * sizeof(char));
if(*(lines + slot) == NULL) exit(EXIT_FAILURE);
strcpy(*(lines+slot),s);
Возможно, попробуйте:
lines[slot] = (char *) malloc((len + 1) * sizeof(char));
if(lines[slot] == NULL) exit(EXIT_FAILURE);
if(strlen(s) <= len){
strcpy(lines[slot],s);
}
else{
/* do something else... */
}
Что касается общей формы, я бы также рекомендовал вам внести несколько стилистических изменений, чтобы сделать все это более читабельным, легким для понимания и устойчивым к ошибкам.
Арифметика с указателями действительна и забавна, но я думаю, что ваши намерения немного более ясны, если вы используете форму массива, например:
free(lines[slot]);
lines[slot] = NULL;
вместо
free(*(lines+slot));
*(lines + slot) = NULL;
Я бы также посоветовал вам использовать меньше статики. Достаточно легко пройти через них в структуре данных и передать их в ваши аксессоры и мутаторы. Становится намного понятнее, где происходит действие, мешающее вам делать такие вещи, как:
static int numlines = 0;
void insert_line(char *s, int len){
int numlines = 5;
где вы можете ввести проблемы с областями видимости, которые просто неэффективны для отладки.
Имеют ли одинаковые значения nlines и numlines?
Позволяет ли вызывающий объект insert_line оставить место для конечного NUL при передаче длины во втором параметре?
Я не уверен, что это связано, но эти две строки кажутся мне подозрительными:
*(lines + slot) = (char *) malloc(len * sizeof(char));
if((lines + slot) == NULL) exit(EXIT_FAILURE);
Сначала вы назначаете возвращение malloc lines [slot]
, а затем проверяете (lines + slot)
, если последнее было NULL, вы разыменовывали NULL указатель!
Также, если lines [slot] (ваш * (lines + slot)) не равен нулю, вы потеряете память, когда назначите ей результат malloc (). Р>
Я предполагаю, что lines
является char
* lines [] `, а слот находится в пределах допустимой границы!
Я согласен с подозрением Ремо об этих двух строках, но не касательно того, на что ушёл Ремо. Мы должны поделиться ссылкой на поиск этой ошибки.
*(lines + slot) = some value
if((lines + slot) == NULL) then die
should be
if(*(lines + slot) == NULL) then die