我有一个单线程的程序,在非debugging模式下运行free()
之后,在某些点一直崩溃。
但是,在debugging模式下, 即使 没有设置中断点,debugging器也会中断正在调用free()
的行。 当我尝试再次跳到下一行时,debugging器再次在同一行中断开。 正常地再次踏步恢复执行。 没有崩溃,没有段错误,没有。
编辑1:与我上面写的相反,在非debugging模式下的崩溃事实certificate是一致的,这使我觉得我在某种 地方写我不应该。 (尽pipe在debugging模式下仍然是一致的)。
在rest时调用堆栈显示一些Windows库函数(我认为)调用free()
语句的函数后调用。 我不知道如何解释它们。 因此,在这种情况下我不知道如何去debugging。
我已经在下面的折点提供了调用堆栈。 有人能指出我可以解决问题的方向吗? 什么可能导致debugging器模式中断?
程序在Windows Vista上运行,使用gcc 4.9.2编译,使用的debugging器是gdb。 假设双释放不是这种情况(我使用::operator new
和::operator delete
重载,可以捕捉到这一点,描述的情况也是一样的,没有这些重载。
请注意,崩溃(或debugging器中的非自愿中断)是一致的。 每次都发生在同一个执行点。
这是初始rest时的调用堆栈:
(请注意, free_wrapper()
是包含导致崩溃/中断的free()
语句的函数。)
#0 0x770186ff ntdll!DbgBreakPoint() (C:\Windows\system32\ntdll.dll:??) #1 0x77082edb ntdll!RtlpNtMakeTemporaryKey() (C:\Windows\system32\ntdll.dll:??) #2 0x7706b953 ntdll!RtlImageRvaToVa() (C:\Windows\system32\ntdll.dll:??) #3 0x77052c4f ntdll!RtlQueryRegistryValues() (C:\Windows\system32\ntdll.dll:??) #4 0x77083f3b ntdll!RtlpNtMakeTemporaryKey() (C:\Windows\system32\ntdll.dll:??) #5 0x7704bcfd ntdll!EtwSendNotification() (C:\Windows\system32\ntdll.dll:??) #6 0x770374d5 ntdll!RtlEnumerateGenericTableWithoutSplaying() (C:\Windows\system32\ntdll.dll:??) #7 0x75829dc6 KERNEL32!HeapFree() (C:\Windows\system32\kernel32.dll:??) #8 0x75a99c03 msvcrt!free() (C:\Windows\system32\msvcrt.dll:??) #9 0x350000 ?? () (??:??) --> #10 0x534020 free_wrapper(pv=0x352af0) (C:\dm\bin\codes\CodeBlocks\ProjTemp\src\Unrelated\MemMgmt.cpp:282) #11 0x407f74 operator delete(pv=0x352af0) (C:\dm\bin\codes\CodeBlocks\ProjTemp\main.cpp:1002) #12 0x629a74 __gnu_cxx::new_allocator<char>::deallocate(this=0x22f718, __p=0x352af0 "\nÿÿÿÿÿÿº\r%") (C:/Program Files/CodeBlocks/MinGW/lib/gcc/mingw32/4.9.2/include/c++/ext/new_allocator.h:110) #13 0x6c2257 std::allocator_traits<std::allocator<char> >::deallocate(__a=..., __p=0x352af0 "\nÿÿÿÿÿÿº\r%", __n=50) (C:/Program Files/CodeBlocks/MinGW/lib/gcc/mingw32/4.9.2/include/c++/bits/alloc_traits.h:383) #14 0x611940 basic_CDataUnit<std::allocator<char> >::~basic_CDataUnit(this=0x22f714, __vtt_parm=0x781df4 <VTT for basic_CDataUnit_TDB<std::allocator<char> >+4>, __in_chrg=<optimized out>) (include/DataUnit/CDataUnit.h:112) #15 0x61dfa1 basic_CDataUnit_TDB<std::allocator<char> >::~basic_CDataUnit_TDB(this=0x22f714, __in_chrg=<optimized out>, __vtt_parm=<optimized out>) (include/DataUnit/CDataUnit_TDB.h:125) #16 0x503898 CTblSegHandle::UpdateChainedRowData(this=0x353cf8, new_row_data=..., old_row_fetch_res=..., vColTypes=..., block_hnd=...) (C:\dm\bin\codes\CodeBlocks\ProjTemp\src\SegHandles\CTblSegHandle.cpp:912) #17 0x502fcc CTblSegHandle::UpdateRowData(this=0x353cf8, new_row_data=..., old_row_fetch_res=..., vColTypes=..., block_hnd=...) (C:\dm\bin\codes\CodeBlocks\ProjTemp\src\SegHandles\CTblSegHandle.cpp:764) #18 0x443272 UpdateRow(row_addr=..., new_data_unit=..., vColTypes=..., block_hnd=..., seg_hnd=...) (C:\dm\bin\codes\CodeBlocks\ProjTemp\src\DbUtilities.cpp:910) #19 0x443470 UpdateRow(row_addr=..., vColValues=..., vColTypes=...) (C:\dm\bin\codes\CodeBlocks\ProjTemp\src\DbUtilities.cpp:935) #20 0x4023e3 test_RowChaining() (C:\dm\bin\codes\CodeBlocks\ProjTemp\main.cpp:234) #21 0x4081c6 main() (C:\dm\bin\codes\CodeBlocks\ProjTemp\main.cpp:1034)
下面是调用堆栈,当我继续下一行时,debugging器最后一次中断,然后恢复正常执行:
#0 0x770186ff ntdll!DbgBreakPoint() (C:\Windows\system32\ntdll.dll:??) #1 0x77082edb ntdll!RtlpNtMakeTemporaryKey() (C:\Windows\system32\ntdll.dll:??) #2 0x77052c7f ntdll!RtlQueryRegistryValues() (C:\Windows\system32\ntdll.dll:??) #3 0x77083f3b ntdll!RtlpNtMakeTemporaryKey() (C:\Windows\system32\ntdll.dll:??) #4 0x7704bcfd ntdll!EtwSendNotification() (C:\Windows\system32\ntdll.dll:??) #5 0x770374d5 ntdll!RtlEnumerateGenericTableWithoutSplaying() (C:\Windows\system32\ntdll.dll:??) #6 0x75829dc6 KERNEL32!HeapFree() (C:\Windows\system32\kernel32.dll:??) #7 0x75a99c03 msvcrt!free() (C:\Windows\system32\msvcrt.dll:??) #8 0x350000 ?? () (??:??) --> #9 0x534020 free_wrapper(pv=0x352af0) (C:\dm\bin\codes\CodeBlocks\ProjTemp\src\Unrelated\MemMgmt.cpp:282) #10 0x407f74 operator delete(pv=0x352af0) (C:\dm\bin\codes\CodeBlocks\ProjTemp\main.cpp:1002) #11 0x629a74 __gnu_cxx::new_allocator<char>::deallocate(this=0x22f718, __p=0x352af0 "\nÿÿÿÿÿÿº\r%") (C:/Program Files/CodeBlocks/MinGW/lib/gcc/mingw32/4.9.2/include/c++/ext/new_allocator.h:110) #12 0x6c2257 std::allocator_traits<std::allocator<char> >::deallocate(__a=..., __p=0x352af0 "\nÿÿÿÿÿÿº\r%", __n=50) (C:/Program Files/CodeBlocks/MinGW/lib/gcc/mingw32/4.9.2/include/c++/bits/alloc_traits.h:383) #13 0x611940 basic_CDataUnit<std::allocator<char> >::~basic_CDataUnit(this=0x22f714, __vtt_parm=0x781df4 <VTT for basic_CDataUnit_TDB<std::allocator<char> >+4>, __in_chrg=<optimized out>) (include/DataUnit/CDataUnit.h:112) #14 0x61dfa1 basic_CDataUnit_TDB<std::allocator<char> >::~basic_CDataUnit_TDB(this=0x22f714, __in_chrg=<optimized out>, __vtt_parm=<optimized out>) (include/DataUnit/CDataUnit_TDB.h:125) #15 0x503898 CTblSegHandle::UpdateChainedRowData(this=0x353cf8, new_row_data=..., old_row_fetch_res=..., vColTypes=..., block_hnd=...) (C:\dm\bin\codes\CodeBlocks\ProjTemp\src\SegHandles\CTblSegHandle.cpp:912) #16 0x502fcc CTblSegHandle::UpdateRowData(this=0x353cf8, new_row_data=..., old_row_fetch_res=..., vColTypes=..., block_hnd=...) (C:\dm\bin\codes\CodeBlocks\ProjTemp\src\SegHandles\CTblSegHandle.cpp:764) #17 0x443272 UpdateRow(row_addr=..., new_data_unit=..., vColTypes=..., block_hnd=..., seg_hnd=...) (C:\dm\bin\codes\CodeBlocks\ProjTemp\src\DbUtilities.cpp:910) #18 0x443470 UpdateRow(row_addr=..., vColValues=..., vColTypes=...) (C:\dm\bin\codes\CodeBlocks\ProjTemp\src\DbUtilities.cpp:935) #19 0x4023e3 test_RowChaining() (C:\dm\bin\codes\CodeBlocks\ProjTemp\main.cpp:234) #20 0x4081c6 main() (C:\dm\bin\codes\CodeBlocks\ProjTemp\main.cpp:1034)
当我看到一个看起来像你的调用堆栈时,最常见的原因是堆损坏。 双释放或试图释放一个从未分配的指针可以有类似的调用堆栈。 由于您将崩溃描述为不一致,导致堆腐败更可能成为候选人。 双释放和释放未分配的指针往往会在同一个地方持续崩溃。 为了寻找这样的问题我通常:
使用整页堆运行应用程序会在每次分配结束时放置一个无法访问的页面,以便在程序访问分配以外的内存时立即停止。 这是根据页面GFlags和PageHeap 。 如果缓冲区溢出导致堆损坏,则该设置应该导致调试程序在发生溢出时中断。
确保在完成调试时禁用页面堆。 在整个页面堆下运行可以通过使每个堆分配消耗整个页面而大大增加应用程序的内存压力。
您可以使用valgrind来检查是否有任何无效的读/写或在您的代码中有任何无效的空闲。 valgrind -v –leak-check = full –show-reachable = yes –log-file = log_valgrind ./Process
log_valgrind将包含无效的读/写。