Sign in to follow this  

Interrupt code for detecting memory corruption

This topic is 3863 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I used to have a piece of code that would let me set a kind of "watch" on a variable, and any time any part of the app would try to modify the variable's contents, it would use an interrupt to stop the debugger and let you see what was trying to modify it. It was a single page of code, written by a guy whose name I think was Mike something, but my memory is foggy. Anyone have a clue what it was called and where to get it? It was really useful, and I think it could help me track down a minor corruption bug I'm experiencing now. edit: I should probably mention that it was in C/C++

Share this post


Link to post
Share on other sites
It would help to know what platform you're on. Aside from that, you can use a debugger (MSVC, WinDbg, GDB, DBX, etc) to do this at runtime instead of programmatically, it's probably much more convenient that way.

Share this post


Link to post
Share on other sites
Under Windows, right?

As outRider says, your debugger is designed for this sort of task - use it if possible. Otherwise, the only way I can think to emulate such functionality is to use hardware breakpoints. I haven't tested this very much, but here is something I've adapted from a user-mode debugger I wrote a while back:

#include <Windows.h>

enum BP_ACCESS
{
BP_WRITE,
BP_READWRITE
};

int CreateHWBP(void* const address, int index, BP_ACCESS access) {
if (index < 0 || index > 3) return -1; // Minimal error-handling

CONTEXT context;
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
DWORD thread_id = GetCurrentThreadId();
HANDLE thread_handle = OpenThread(THREAD_ALL_ACCESS, false, thread_id);
GetThreadContext(thread_handle, &context);

// Reset
context.Dr7 &= ~(3 << (2 * index));
context.Dr7 &= ~(3 << (16 + 2 * index));
context.Dr7 &= ~(3 << (24 + 2 * index));

// Enable
context.Dr7 |= (1 << (2 * index));

// Address
switch (index) {
case 0:
context.Dr0 = reinterpret_cast<DWORD> (address);
break;
case 1:
context.Dr1 = reinterpret_cast<DWORD> (address);
break;
case 2:
context.Dr2 = reinterpret_cast<DWORD> (address);
break;
case 3:
context.Dr3 = reinterpret_cast<DWORD> (address);
break;
}

// Access
switch (access) {
case BP_WRITE:
context.Dr7 |= (1 << (16 + 2 * index));
break;
case BP_READWRITE:
context.Dr7 |= (3 << (16 + 2 * index));
break;
default:
break;
}

SetThreadContext(thread_handle, &context);
CloseHandle(thread_handle);
return 0; // Success
}

int DestroyHWBP(int index) {
if (index < 0 || index > 3) return -1;

CONTEXT context;
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
DWORD thread_id = GetCurrentThreadId();
HANDLE thread_handle = OpenThread(THREAD_ALL_ACCESS, false, thread_id);
GetThreadContext(thread_handle, &context);

switch (index) {
case 0:
context.Dr0 = 0;
break;
case 1:
context.Dr1 = 0;
break;
case 2:
context.Dr2 = 0;
break;
case 3:
context.Dr3 = 0;
break;
}

SetThreadContext(thread_handle, &context);
CloseHandle(thread_handle);
return 0; // Success
}


It isn't very portable, and certainly not 64-bit-compliant. Neither is it compatible with Visual Studio's tracing.

Call CreateHWBP with a pointer to the watch variable, passing zero as the index and BP_WRITE or BP_READWRITE as appropriate. If the local process violates the break condition, a EXCEPTION_SINGLE_STEP is raised. Without a debugger, this will fall through to whatever handlers you have installed, probably resulting in a crash. Under Visual Studio, the exception will be caught and handled internally. By the looks of things, VS uses the same technique for its own breakpoints. Moreover, it ignores any single-step errors in places it isn't using itself. This has a few consequences:

1. Setting any breakpoints in the debugger will overwrite your user-breakpoint.
2. Calling the function after having set a breakpoint in the IDE will similarly result in an overwrite.
3. You may only have one such breakpoint going at a time, with index = 0. Putting index = 1, 2, 3 doesn't seem to do anything.

You can remove the breakpoint by calling DestroyHWBP with the corresponding index.

Admiral

Share this post


Link to post
Share on other sites
I'm using VS2005 - what's the command(s) to setup a variable break in that IDE? I know you can setup breaks with equation checks, but how do I set it up to break any time a variable is altered?

Share this post


Link to post
Share on other sites
Debug -> New Breakpoint -> New Data Breakpoint
Enter the address of the variable to watch (E.g. &m_theVariableName) and the number of bytes to watch (E.g. 4 for an int, 2 for a short, etc), then hit "OK"

Share this post


Link to post
Share on other sites
Hardware supported breakpoints use... hardware... so you only can watch so many bytes. You can have either one or two, each 4 bytes long, on most hardware. If you go outside of this, it has the enumate the code. This is extremely slow.

HW breakpoints are a great tool - everyone should know about them. :)

Share this post


Link to post
Share on other sites
Ah see, those data breakpoints are not much use for what I was after - for starters they can only be set once the program is running, and then you have to set them again every time you run it.

TheAdmiral has posted some nice code there - it wasn't the exact same code I had before, but it looks like it does the same kinda thing - you add a call in your code to set a HW breakpoint on the variable space you're interested in, and hey presto.

Thanks Admiral.

Share this post


Link to post
Share on other sites
If you're only watching pointers, it might be better to create a 'DebugPointer' template class with overloaded operators. You can call 'DebugBreak()' from the windows API to break at any time inside the various operators. Optionally, use IsDebuggerPresent() so that you only break when a debugger is watching, and you could use #ifdef blocks to entirely remove the test in release builds.

Share this post


Link to post
Share on other sites
Quote:
Original post by BrianL
Hardware supported breakpoints use... hardware... so you only can watch so many bytes. You can have either one or two, each 4 bytes long, on most hardware.

For the sake of correctness, I'm not sure how things used to be, but since the 486, Intel set the standard as four hardware breakpoints per task (hence DR1 through DR4 being address registers). And although it's most common to use dword breakpoints, the processor supports HWBPs of size 1, 2, or 4 bytes.

Admiral

Share this post


Link to post
Share on other sites

This topic is 3863 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this