Wednesday, June 18, 2014

Managing ASSERT & NT_ASSERT in WinDBG & KD

What are ASSERTs and how to use them:

In general, Windows developers may use ASSERT and NT_ASSERT to validate excepted assumptions in their code.  In CHK (checked non-optimized) binaries, an exception will be thrown if the expression does not evaluate to true.

For example, you may have an assumption in a function, that a pointer should never be NULL and the buffer size should be less than 1k.  Then you can write an ASSERT like this:

ASSERT(pBuff && (cbBuff < 1024));

This assertion will fire if the expression is false, or in this case: !pBuff || cbBuff >= 1024.

0:003> p
Assertion s:\dllsrv\info.cpp(83): pBuff && (cbBuff < 1024)
...

There are differences between the two, but normally it is better to use NT_ASSERT, but this is not what this article is about.  There is also a NT_VERIFY which will assert even in FRE (free optimized binaries), but I can 't think of any reasons of the top of my head why you would need to use it.

As a rule of thumb, you shouldn't use ASSERTs too heavily.  For instance, in my example, you can validate the same thing using SAL annotations where bugs can be found at compile time with static analysis tools like prefast which is always preferable to runtime debugging.  You may consider adding ASSERTs while developing your code, and removing a bunch of them once it has stabilized.

ASSERTs in WinDBG & KD

Normally when I am testing my code, I run my code under WinDBG or KD.  I normally copy private CHK versions of my binaries with symbols.  It is always a good idea to enable application verifier as well, or use gflags to add standard checks.

In the simplest form, lets say your ASSERT throws an exception because it evaluates false, you do the normal debugging thing and figure out why your assumptions were not correct, fix the bug(s), replace the binary, and restart the test.  That is the point of the asset after all.

But, lets say you want to continue on.  What are the commands to do that?

gh - this is the basic one.  It is like pressing g or F5 except you are telling to not worry about the exception.

ah - you use ah to control a specific assert.  For instance, you can use ahi to ignore an assertion, if it is noisy and you don't want or can't change the binary to remove or fix it.

sx - is used to control exceptions globally.  sx* asrt will disable all asserts for instance.