Archive for September, 2006

NdisMRegisterDevice and object lifetimes

Wednesday, September 13th, 2006

NdisMRegisterDevice was introduced back in the NDIS 5 days to allow for the creation of a control device in an NDIS miniport. The control device mechanism is used a lot by IM driver writers (configuring firewall rules, QoS, whatever). Some people also use them for miniports, such as virtual Ethernet miniports and NDIS-WDM drivers.

One thing that’s not clear from the documentation, though, is what sort of lifetime the device object has. Living in the nice safe world of the NDIS Miniport model, it’s easy to get lulled into a false sense of security regarding synchronization. NDIS is generally pretty good at managing device state, synchronizing with MiniportHalt(), and so on.

But when you create a device object with NdisMRegisterDevice(), NDIS basically turns all state management over to you. That means that you have to be cognizant of the different lifetime a device object has vs. a miniport object. In particular, a control device can indeed outlive a miniport!

For example, say you have a memory block that you allocate during MiniportInitialize() and free during MiniportHalt() – not an uncommon strategy. If your dispatch routines for your control device need to reference that memory, you have to be careful about how you handle it. MiniportHalt() is NOT synchronized with these control device dispatch routines, so your dispatch routines can indeed be called after MiniportHalt() is called. In fact, there’s no great way to tell when your dispatch routines will not be called any more, and there’s no way to tell if a thread is executing in a dispatch routine at the time you deregister the device.

All of this means that you have to be more clever in the way you manage that shared memory block. One possibility is reference counting the block itself – Reference the block on creation in MiniportInit(), dereference it on MiniportHalt(), and take/release references as necessary in your dispatch routines. This must be done in an interlocked and race-proof way; NdisInterlockedIncrement() and friends are helpful for this.

This is a subtle point, and one that is not well documented. It stems in large part from the absence of device extension access for control devices created this way; that’s the mechanism that the OS uses to tie a memory block’s lifetime to a device object’s (as opposed to a miniport’s). But, as long as you’re aware of the issue, it can be worked around.

Raymond explains the setup of set up

Tuesday, September 12th, 2006

Raymond sheds some light on one of my favorite pet peeves.

What are asserts good for?

Sunday, September 10th, 2006

The ASSERT() macro (assert() in userland) is one of the more useful testing tools you can build into your code. By crashing into a debugger the instant one of your assumptions is violated, ASSERT() gives you a great chance to catch a caller doing something it shouldn’t, or to cause you to re-evaluate your assumptions.

I see a lot of first-time ASSERT users do something like this:

char x(char *a)
{
	ASSERT(a);

	return *a;
}

Yes, this ASSERT will verify that you haven’t passed a null pointer to x(), but… so will the next line. If you’re just going to move a guaranteed crash from one spot in the function to another, I’m not sure ASSERT adds much value.

On the other hand, the situation changes when you start masking errors by being fault-tolerant:

char x(char *a)
{
	ASSERT(a);

	if(!a)
		return 0;

	return *a;
}

In this case, the ASSERT is doing something useful – it’s restoring the crash that you would otherwise have masked away, but only in debug builds where you want it.

Another useful form of ASSERT is as a logic check. For instance:

int x(char *a)
{
	/*
	 * It doesn't make sense for the
	 * first character to be NULL
	 */
	ASSERT(*a);

	return *a;
}

This kind of check can be the most useful for finding subtle design problems. Use them liberally during development, and leave them there for the next time you have to work on the code.

And, as an excellent side benefit, ASSERT macros make your code easier to maintain for the next coder who comes along. Not only are your assumptions clearly and precisely documented, but the presence of the ASSERTs will help to prevent the new person from breaking anything by pointing out any problems with changes.

The final four SSN digits strike again

Wednesday, September 6th, 2006

Still heads-down and coding like a mad fool, but I couldn’t help but point this out. You may have heard about the regrettable HP director spying case. The details are in the link, but the high-level point is that someone posed as Tom Perkins (of Kleiner Perkins fame) to get access to his phone records.

Guess how they did it?

The person registering the online account did so through the Internet and provided your telephone number and the last four digits of your Social Security Number to identify himself/herself as the authorized account holder.

No wonder Bruce Schnier ranks the SSN as the worst personal privacy debacle of all time.

Remember: NEVER give out the last four digits of your SSN..