Можно ли предположить, что куча не была повреждена, если _heapchk () возвращает "хорошо"? - PullRequest
1 голос
/ 22 февраля 2011

В Visual C ++ использование new[] для выделения массива объектов, а затем delete (не delete[]) по умолчанию запускает неопределенное поведение следующего вида .

Для вызова деструкторов для всех объектов необходимо знать количество объектов, поэтому Visual C ++ вызывает ::operator new[](), чтобы выделить немного больший буфер, помещает количество элементов в начало, затем вызывает конструкторы и возвращает указатель на первый объект. Когда delete выполнено, он уничтожает только первый объект, а затем передает неверный указатель в ::operator delete(), который по умолчанию реализуется точно так же, как ::operator delete[]().

Если следующее

class Class {
public:
   ~Class() { Sleep( 0 );}
};

delete new Class[1];

компилируется в конфигурации выпуска и запускается под отладчиком, программа останавливается с точкой останова:

ntdll.dll!_DbgBreakPoint@0()    
ntdll.dll!_RtlpBreakPointHeap@4()  + 0x28 bytes 
ntdll.dll!_RtlpValidateHeapEntry@12()  + 0x113 bytes    
ntdll.dll!_RtlDebugFreeHeap@12()  + 0x97 bytes  
ntdll.dll!_RtlFreeHeapSlowly@12()  + 0x246cf bytes  
ntdll.dll!_RtlFreeHeap@12()  + 0x17646 bytes    
sample.exe!free(void * pBlock=0x0003339c)  Line 110 C
sample.exe!main()  Line 48  C++
sample.exe!__tmainCRTStartup()  Line 266 + 0x12 bytes   C
kernel32.dll!_BaseProcessStart@4()  + 0x23 bytes

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

Я пытался позвонить _heapchk() до и после этой строки, и на удивление он возвращает _HEAPOK оба раза. Я также включил обнаружение утечек памяти , и по окончании программы утечек не было.

Можно ли предположить, что куча полностью исправна, если _heapchk() вернет _HEAPOK?

Ответы [ 4 ]

3 голосов
/ 22 февраля 2011

С документация (упор мой):

Функция _heapchk помогает отлаживать проблемы, связанные с кучей, проверяя минимальную согласованность кучи .

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

2 голосов
/ 22 февраля 2011

Не могу сказать точно, но я немного поиграл с этим и заметил две вещи:

  1. В сборках релиза компилятор иногда вызывает вызов ассемблера «оператор delete []», даже когда код C ++ использует обычное удаление.
  2. В сборках выпуска при использовании неправильного удаления CRT выявляет несоответствие и сообщает об этом через RtlpLogHeapFailure (бог знает, что это значит ...).

Я просто размышляю здесь, но я предполагаю, что часть удаления, которая обрабатывает кучу, умнее, чем вы думаете. У него действительно есть способ узнать, что вы отправляете, и обращаться с ним соответствующим образом. Таким образом, в отладочной сборке вы получите утверждение из дополнительных отладочных тестов, но на более низком уровне куча все еще может защитить себя и выполнить правильное действие, не будучи поврежденным. Так что, если это действительно так, то на VC ++ тип удаления просто влияет на разрушения, и часть кучи выполняется в любом случае правильно. Другие компиляторы могут вести себя по-другому.

И именно поэтому _heapchk () не вернет ошибку ...

1 голос
/ 22 февраля 2011

Вы имеете в виду, что вы вызываете функцию после вызова неопределенного поведения и все еще хотите доверять результату? ; -)

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

Другие необычные обстоятельства:
- Вы звоните новым и удаляете в том же заявлении.
- Вы выделяете только один элемент.
- Вы делаете это только в одном месте во всей программе.
- деструктор не делает ничего значительного для распределения памяти.
Все это может повлиять на то, как оптимизатор создает код, и, как сказал Эран, - компилятор может легко увидеть все это и понять, что вы делаете. Это не глупо!

1 голос
/ 22 февраля 2011

Нет, _heapchk возвращает _HEAPOK просто означает, что не может найти проблему или что куча не поддерживает проверку.

Я бы сказал, что более вероятно, что вы удаляете неинициализированный указатель, когдаВы получаете эту ошибку.

...