From b2b68b8a78ee9941fc2135f0eb74b3dd192dfb87 Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Sat, 17 Oct 2026 21:40:38 +0200 Subject: [PATCH] Clear software breakpoint records after memory is unmapped DLL unload events arrive after the image memory is gone. If restoring the original byte fails, allow deletion when VirtualQueryEx confirms the address is free or reserved, so stale breakpoint and callback records cannot block installation after reload. Keep restoration failures in committed memory and failed memory queries as errors, preserving the breakpoint state for a retry. --- GleeBug/Debugger.Process.Breakpoint.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/GleeBug/Debugger.Process.Breakpoint.cpp b/GleeBug/Debugger.Process.Breakpoint.cpp index b8e1b56..1340935 100644 --- a/GleeBug/Debugger.Process.Breakpoint.cpp +++ b/GleeBug/Debugger.Process.Breakpoint.cpp @@ -69,10 +69,18 @@ namespace GleeBug return false; const auto & info = found->second; - //restore the breakpoint bytes + // Restore the breakpoint bytes if the memory still exists. DLL unload + // events arrive after the image has been unmapped, so there is nothing + // to restore in that case, but the breakpoint records must be removed. if(!MemWriteUnsafe(address, info.internal.software.oldbytes, info.internal.software.size)) - return false; - FlushInstructionCache(hProcess, nullptr, 0); + { + MEMORY_BASIC_INFORMATION mbi = {}; + if(!VirtualQueryEx(hProcess, LPCVOID(address), &mbi, sizeof(mbi)) || + (mbi.State != MEM_FREE && mbi.State != MEM_RESERVE)) + return false; + } + else + FlushInstructionCache(hProcess, nullptr, 0); recentlyDeletedSwbp.insert(address);