Suppose to have the ability to add dozens of breakpoints into your program main error detection points, whenever you start a debugging session.
This should allow you to easily track down some hidden/unnoticed problems.
For example, suppose to have a C function like the below one:
__MYOBJECTDATA * WINAPI MYOBJGetPtr (HANDLE hMyObject) { __MYOBJECTDATA *pObj; pObj = (__MYOBJECTDATA *) hMyObject; __try { if ((pObj != NULL) && !<verify *pOBJ>) pObj = NULL; } __except (EXCEPTION_EXECUTE_HANDLER) { pObj = NULL; } return pObj; }
This function transforms a handle to a data ptr, only if it passes the proper verification steps.
It is written to properly process 3 values’ types:
- valid handles
- NULL handles
- invalid handles (not NULL values that don’t pass the verification process).
This last type may usually hide some upstream error, and it usually needs immediate attention to track & fix the problem.
Usually, we can fix them quickly, if we catch them.
Writing a Debugger-Aware code
Windows gives us the ability to easily write Debugger-Aware code by using a couple of system API:
- IsDebuggerPresent() – it tests if a debugging session is active.
- DebugBreak() – it triggers a debugger breakpoint.
Now we can update our function, to trigger a debugger breakpoint on every invalid handle values.
__MYOBJECTDATA * WINAPI MYOBJGetPtr (HANDLE hMyObject) { __MYOBJECTDATA *pObj; pObj = (__MYOBJECTDATA *) hMyObject; __try { if ((pObj != NULL) && !<verify *pOBJ>) pObj = NULL; } __except (EXCEPTION_EXECUTE_HANDLER) { pObj = NULL; } #ifdef _DEBUG if (IsDebuggerPresent () && (hMyObject != NULL) && (pObj == NULL)) DebugBreak (); #endif return pObj; }
With only 4 lines of code, the debug version of this function is now clever enough to call us for any invalid handle values that occurred, only when a debugging session is active.
This will allow us, to backstep from the function for the call stack, and fix any improper handle usage.
I find the reach of this hint quite intriguing…