как проверить последствия использования free () с new [] - PullRequest
3 голосов
/ 04 октября 2011

Процесс завершается с SIGSEV, а обратные следы указывают на повреждение памяти.В отчете Valgrind указано, что существует некоторое «Несоответствие свободной», то есть память, выделенная с помощью new [], освобождается с помощью free ().

Я нашел следующую информацию из cert.org

Другая потенциальная проблема заключается в том, что при передаче указателя на массив, выделенный с оператором, новым для оператора delete (), возможно, что когда free () вызывается оператором delete () (как это часто бывает во многихреализации, хотя это и не требуется стандартом C ++), указатель, переданный free (), не является тем, который был возвращен вызовом malloc ().Это связано с тем, что первые четыре байта, возвращаемые функцией malloc () при вызове оператором new, обычно используются для хранения размера массива (опять же, не определяется стандартом, но обычно), поэтому указатель, возвращаемый оператором new, фактически указываетпо адресу, который составляет четыре байта от указателя, возвращенного функцией malloc ().Следовательно, free () будет читать неправильный размер для освобождения, и это может привести к проблемам с повреждением памяти в куче.

Вопрос в том, как я могу продемонстрировать, что free () освобождает неправильный размер?Кто-нибудь может подсказать, как проверить, что это происходит в моей среде, может быть, с помощью gdb или каких-либо других инструментов?

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

Ответы [ 6 ]

4 голосов
/ 04 октября 2011

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

Кто-нибудь может подсказать, как проверить, что это происходит в моей среде, возможно, с помощью gdb или любых других инструментов?

Вы уже запустили инструмент, который сказал вам, что это то, что происходит .Зачем вам тогда запускать другой инструмент, чтобы убедиться, что «это действительно то, что происходит»?

Вы не соответствуете некоторым вызовам free в соответствии с Valgrind.Это проблема, и это то, что вам нужно исправить.

Пока эта проблема существует, она может иметь миллионы различных последствий, одно из которых - это то, что было описано в тексте.Вы цитировали.Но вам не нужно знать , какой из этого миллиона последствий на самом деле происходит в вашей программе, потому что это всего лишь симптомы, , и вы уже знаете, в чем причина .

Единственный гарантированный эффект при несоответствии free / delete заключается в том, что «что-то происходит».И что это за "что-то"?Никто не может сказать.

Если вы намеренно не пытаетесь написать плохое программное обеспечение, вам следует устранить проблему у источника, и то, что вы просите, не поможет вам в этом.

2 голосов
/ 04 октября 2011

То есть реализация определена. Вы не можете в общем «продемонстрировать» это, хотя вы можете использовать определенный компилятор / toolchain / libc.

Я предлагаю вам использовать valgrind для выявления таких ошибок.

Более подробные списки таких инструментов можно найти на SO

Редактировать Вот рекомендуемый пост с таким списком: Проблема с инструментами проверки утечки памяти в Linux

1 голос
/ 04 октября 2011

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

В зависимости от реализации, сообщение об ошибке, которое приходит с SIGSEGV, вероятно, скажет вам, что переданный указатель недействителен (или не был выделен, или что-то подобное).

1 голос
/ 04 октября 2011

Вы можете попробовать использовать Дума (http://duma.sourceforge.net/).Он обнаруживает несоответствия malloc / free new / delete.Он также проверяет двойное освобождение и изменение памяти после вызова free / delete

0 голосов
/ 04 октября 2011

Вот пример кода, который демонстрирует проблему:

#include <stdlib.h>

struct A
{ int i; };

struct B
{
  ~B(){ }
  int i;
};

int main()
{
  A * a = new A[10];
  free(a);

  B * b = new B[10];
  free(b);
}

Если вы запустите это с ltrace под Linux, вы увидите что-то вроде:

_Znaj(40, 0x293324, 0x292ff4, 0xbfeaca28, 0x165d35) = 0x88f7008
free(0x088f7008)                                 = <void>
_Znaj(44, 0x293324, 0x292ff4, 0xbfeaca28, 0x165d35) = 0x88f7008
free(0x088f700c

Итак, во втором случаеосвобождаемый указатель не соответствует назначаемому (из-за того, что пользователь объявил деструктор в B).

Конечно, несоответствие между new [] и free является неопределенным поведением, но это не всегда приводит кв SIGSEGVs на практике.

0 голосов
/ 04 октября 2011

Если это случай объяснения и «демонстрации» этого другим, я бы предложил вам объяснить, почему это опасно, не демонстрируя. В этом случае должно быть достаточно объяснений, чтобы ясно показать всем подводные камни. Если вы настаиваете на демонстрации, вы можете создать буфер с использованием malloc и один с использованием new [] и показать содержимое областей памяти, в которых хранится выделенный размер, используемый с malloc, и содержимое, используемое new. Просто наблюдаю разницу. Но с другой стороны, поведение зависит от реализации, как объяснил sehe.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...