Есть прога, которая хорошо работает в 32 бит, пересобираю ее на 64 бита. Помимо прочего, всплывают ошибки heap corruption при вызове HeapFree. Я понимаю, что где-то перезаписывается граница массива и при освобождении все падает. Но вручную сложно искать, мб есть какие-то инструменты, профилировщики, логгеры для памяти?
Я бы для начала попробовал статические анализаторы, типа cppcheck и скаченной с торрентов pvs studio. Ты удивишься, сколько они косяков находят, о которых ты даже не думал. В частности для порта с х86 на х64 могут помочь.
Это тот софт, что с белым конем? Спасибо, он вроде как даже бесплатно доступен, если комент добавить. Правда, не юзал ни разу.
M0rg0t, Там множество механизмов, отладочных да что угодно. при каждой манипуляции памятью может выполнять полный анализ вызова - блоков, cтека и тп.
Подниму тему. Есть стандартный код, выделение памяти через HeapAlloc,освобождение через HeapFree, и вот он иногда падает на heapfree. Причина - перезапись границ буфера. Хотел это логировать, но почему-то обработчики исключений не ловят его нифига. Точнее так: Код (ASM): .486 .model flat,stdcall option casemap:none seh1 proto pExcept:dword include \masm32\include\windows.inc include \masm32\macros\macros.asm uselib kernel32,user32 .data .data? hH dd ? lpMem dd ? .code start: invoke SetUnhandledExceptionFilter,offset seh1 invoke HeapCreate,HEAP_GENERATE_EXCEPTIONS, 10000, 0 mov hH,eax invoke HeapAlloc,hH, 0, 32 mov lpMem,eax mov edi,lpMem xor eax,eax mov al,'A' mov ecx,91 rep stosb invoke HeapFree,hH, 0, lpMem exit seh1 proc pExcept:dword invoke OutputDebugStringA,chr$("seh..") ret seh1 endp end start Асм ловит все норм, но когда аналогичный код на Си, то обработчик не мой, а ntdll.__except_handler4 . VEH также падает туда. Где студия хранит все это и как отключить?
catch ловит только плюсовые исключения, брошенные через throw. Исключения, брошенные процессором или вручную через RtlRaiseException, она не поймает. Зато поймает __try..__except. Но если надо ловить в контексте произвольных потоков в чужом коде, то только SetUnhandledExceptionFilter/AddVectoredExceptionHandler. M0rg0t, покажи сишный вариант и проверь все статусы у функций, что они возвращают. Попробуй кинуть исключение вручную через RtlRaiseException и посмотри, поймаешь ли ты его.
TermoSINteZ, не пробовал, ибо пишу на чистом Си, и зачастую без CRT, т.е. мне доступен только винапи SEH / VEH. HoShiMin, RaiseException ловлю успешно. По статусам - все функции вроде работают норм, т.е. HeapCreate, Alloc возвращают валидные значения, а падает ес-но на HeapFree, только падает не в тот обработчик, что надо. Код (C): LONG WINAPI seh1(__in struct _EXCEPTION_POINTERS* ExceptionInfo) { char buf[64]; wsprintfA(buf, "err 0x%x in 0x%x", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress); OutputDebugStringA(buf); HANDLE hF = CreateFileW(L"1.dmp", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hF, 0x00000002, NULL, NULL, NULL); return EXCEPTION_EXECUTE_HANDLER; } void test_heap() { HANDLE hH = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 10000, 0); //test LPBYTE lpMem = HeapAlloc(hH, 0, 32); memset(lpMem, 'A', 33); HeapFree(hH, 0, lpMem); } int wmain(_In_ int argc, _In_reads_(argc) _Pre_z_ wchar_t** argv, _In_z_ wchar_t** envp) { SetUnhandledExceptionFilter(seh1); //AddVectoredExceptionHandler(1, seh1); //RaiseException(0x123456, 0, 0, NULL); test_heap(); return 0; }
хм. а ведь и правда - это неуловимое исключение, то есть есть определенные ошибки работы менеджера памяти кучи, который считает, что исключение критическое, и прибивает программу игнорируя ваши установленные исключения Цитата И да, это еще и зависит от ОС на которой вы запускаете.
но масм ведь как-то ловит. Вот почему много лет не хотел переходить на Си, и не хочу на плюсы и прочие расты - там компилятор считает, что он умнее человека. Как же тогда быть с этим хип корапшн? Пробовал статические анализаторы, но увы, часто бывает что буфер выделила 1 функция, его передали в другую, третью, и где-то оно падает.
Студии под рукой нет, из-под гцц приведенный исходник дает срабатывание обработчика. Наверное ответ кроется в самом бинарнике из-под студии, где обработчик не устанавливается вовсе, потому что студия.
f13nd, да, студия "особенный" компилятор, но вроде чистый код, т.е. компилировал с флагами без црт и прочего. В общем, Thetrik нашел решение - надо указывать MajorOperation System в 4 (как делает масм, студия ставит 6), тогда почему-то все работает как надо.
M0rg0t, на линуксе с помощью санитайзеров все ловится. В винде - может интел Vtune сможет увидеть проблемы. Но обычно я пишу код так, чтоб можно было всегда проследить кому сколько куда выделилось и освободилось. если затрешь по-больше чем на 1 байт , то не поймает ) Проверял на win10 x64. Код на фасме Код (ASM): format PE64 GUI entry start include 'fasmw\\INCLUDE\\win64a.inc' section '.text' code readable executable start: sub rsp,8*5 lea rcx, [msgst] call [OutputDebugStringA] lea rcx,[seh1] call [SetUnhandledExceptionFilter] xor r8, r8 mov rdx, 10000 mov rcx, 4 call [HeapCreate] mov [hH],rax mov r8, 32 mov rdx, 0 mov rcx, [hH] call [HeapAlloc] mov [lpMem],rax mov rdi,rax xor rax,rax mov al,'A' mov rcx,33 ; try 91 too ^_^ rep stosb mov r8, [lpMem] mov rdx, 0 mov rcx, [hH] call [HeapFree] lea rcx, [msg] call [OutputDebugStringA] xor rax, rax call [ExitProcess] seh1: lea rcx, [msge] call [OutputDebugStringA] ret section '.data' data readable writeable hH dq ? lpMem dq ? msg db 'seh',0 msgst db 'start seh test',0 msge db 'end test',0 section 'idata' import data readable writeable dd 0,0,0,RVA kernel_name,RVA kernel_table dd 0,0,0,RVA user_name,RVA user_table dd 0,0,0,0,0 kernel_table: GetLastError dq RVA _GetLastError LoadLibraryA dq RVA _LoadLibraryA ExitProcess dq RVA _ExitProcess SetUnhandledExceptionFilter dq RVA _SetUnhandledExceptionFilter HeapCreate dq RVA _HeapCreate HeapAlloc dq RVA _HeapAlloc HeapFree dq RVA _HeapFree OutputDebugStringA dq RVA _OutputDebugStringA dq 0 user_table: MessageBoxA dq RVA _MessageBoxA dq 0 kernel_name db 'KERNEL32.DLL',0 user_name db 'USER32.DLL',0 _GetLastError dw 0 db 'GetLastError',0 _LoadLibraryA dw 0 db 'LoadLibraryA',0 _ExitProcess dw 0 db 'ExitProcess',0 _SetUnhandledExceptionFilter dw 0 db 'SetUnhandledExceptionFilter',0 _HeapCreate dw 0 db 'HeapCreate',0 _HeapAlloc dw 0 db 'HeapAlloc', 0 _HeapFree dw 0 db 'HeapFree', 0 _OutputDebugStringA dw 0 db 'OutputDebugStringA', 0 _MessageBoxA dw 0 db 'MessageBoxA',0
TermoSINteZ, у меня аналогично win10x64, и все ловит. Т.е. прога не падает, пишет только лог в dbgview. Странно это всё. --- Сообщение объединено, 10 июл 2022 --- TermoSINteZ, а хотя да,- ставлю 33 , ловит; ставлю 91, не ловит. В чем суть? Что хип выделяется блоками какого-то размера, и до него можно безопасно перезаписывать границу?