NDIS API breakage
I have been spending some time polishing up a driver I’m working on, and today I got to the point in my testing that it was time for Driver Verifier’s Low Resources Simulation. Everything was moving along nicely, when all of a sudden I glanced up and noticed a kd> prompt staring at me. I always hate finding bugchecks that late in the test process.
It was broken into an area of code that I didn’t write, so I wasn’t immediately familiar with how it worked. The top of the stack was inside a call to NdisReadConfiguration(). Looking at the code, it seemed like an impossible bugcheck - I had already validated all of my buffers prior to that point. The call immediately above was to NdisInitializeString() - that can’t fail, right? After all, it return VOID… Hmmm…
Then I noticed a missing L before the string literal I was trying to initialize. That couldn’t work… but why wasn’t the compiler complaining? I was compiling on /W3 after all. No, in fact, for historical reasons going back before Windows NT, NdisInitializeString takes a regular 8-bit character pointer. But the docs clearly say that NDIS_STRING is UNICODE_STRING in Windows 2000+. Unicode is bigger than ANSI by double; where does it get the extra memory from for the conversion? Yep, that’s right, it’s calling ExAllocatePoolWithTag(). Can that fail? Yes.
So I cracked the function open in WinDbg and sure enough, it tries to allocate memory (under the tag NDst). After setting string.Buffer to the returned pointer, it checks for failure and just returns if the allocation failed. That means that Buffer is NULL, so at least there’s a way of testing for this condition - as long as Microsoft doesn’t change the code!
On further inspection of the documentation, it turns out that you’re supposed to pass in a “null” NDIS_STRING for initialization by NdisInitializeString(). I wasn’t sure what that meant at the time, but on further review, it looks like it would be a good idea to zero-fill the NDIS_STRING before passing it to this API, just in case the internal implementation changes (e.g. if they test the return from ExAllocatePoolWithTag() before assigning it to .Buffer).
And the icing on the cake is that NdisFreeString is just a macro for NdisFreeMemory, which frees to the null tag.
Now I just have to figure out why the thing Just Doesn’t Work™ on Windows XP gold. I love NDIS!
April 29th, 2006 at 4:14 pm
[…] So, back to testing. What a pain. I discovered several interesting NDIS-related bugs along the way, though, so it wasn’t a total loss. NdisInitializeString() is just weird, and to add to that, there are a couple of minor type bugs in NdisInitializeString() (again!) and NdisMEthIndicateReceive(), where things that are documented as taking VOID are actually prototyped as taking PUCHAR. […]