Простая логика Инспектора



- Крюшо, в чем дело?
- Мы только что приехали!
- Вижу. А перед этим?
- А перед этим выехали..
(Жандарм и инопланетяне)



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

В этот раз речь пойдет об уже набившей оскомину диагностике “Mismatched Allocation/Deallocation”, которую выдает Inspector XE при анализе ошибок памями (Memory Checking). Простые жители Сан-Тропе недоумевают, почему в списке подозреваемых оказываются совершенно невинные объекты. В их действиях, видимо, совершенно нет ничего криминального. Ну посудите сами, где здесь нарушения и почему Инспектор подозревает в несовпадении парных операций выделения и уничножения объекта памяти в куче?


	Ray *p = NULL;

	const int nsize=4;

	CMemAllocTestDlg dlg;

	m_pMainWnd = &dlg;

	INT_PTR nResponse = dlg.DoModal();


	if (nResponse == IDOK){

		p = new Ray[nsize];	}

	else if (nResponse == IDCANCEL){

	}


	if (p != NULL)

		delete [] p;






Первой зацепкой в данном запутанном деле должно стать то, что в отчете Memory Checking анализа в поле Allocation Site (место выделеня памяти) указан не пользовательский модуль с кодом p = new Ray[nsize], а отладочная версия модуля mfc100.dll – его видно, если пойти вверх по стеку вызовов в Инспекторе. Это очень важная зацепка. Иногда ее может не быть, если например библиотека MFC, которая используется в приложении, расположена где-нибудь в нестандартном месте или вообще отсутствует в системных путях, и приставлена к программе в какой-нибудь директории.



Далее, пользуясь этой зацепкой, раскручиваем стек вызовов с помощью республиканской гвардии, то есть отладчика. Остановим выполнение программы на строчке с вызовом оператора new, и «прыгнем» в этот вызов. И что мы видим? Оказывается, коварные инопланетяне подменили всем известного и знакомого горожанина new своим железным макросом NEW_DEBUG,


#ifdef _DEBUG

#define new DEBUG_NEW

#endif



который, если ему постучать кулаком по спине, отзовется гулким эхом _malloc_dbg (оканчивающийся вызовом имплементации функции malloc() с помощью HeapAlloc() в malloc.c):



Да, Инспектор прост и логичен: он, исследуя (следы преступления) исполнение кода сопоставил два оператора, которые выделяли и уничтожали объект. В первом случае new оказался подозрительным, был опрошен с пристрастием, и признался что он malloc. А вот во втором от встречает delete[], интерпретировал его как деаллокатор, о чем смело и рапортовал шефу.Он не стал раскручивать стек, так как внутренняи имплементация оператора его не интересует (а зря, так как имплементация delete тоже оканчивается вызовом HeapFree()).







Как не попасться Инспектору и избежать задержания и доставления в участок? Довольно просто. Нужно переопределить оператор new для ваших модулей, или убрать переопределение, которое установили инопланетяне при генерировании шаблона проекта в Visual Studio. Кстати, необходимо помнить, что заголовочный файл "afxtempl.h" тоже переопределяет этот оператор.

Надо отметить, что с годами работы Испектор становится все опытнее и мудрее. Скоро, возможно, он научится распознавать инопланетные клоны «на глаз», и будет их игнорировать, если они не нарушают порядок в маленьком городе. В конеце-концов, они прилетели к нам с миром, и совсем не мечтают о его завоевании. Но это не значит, что Инспектор потеряет бдительность. Он все так же следит за всем, что происходит вокруг.


Cсылки на прошлые посты об Инспекторе:
Имеет ли Инспектор право на ошибку?
Куда смотрит Инспектор?
Когда Инспектор слишком строг
Когда Inspector мышей не ловит
Разгадываем загадку многопоточности
Загадочная многопоточность и Parallel Inspector

For more complete information about compiler optimizations, see our Optimization Notice.