Tech News
← Back to articles

Uninitialized garbage on ia64 can be deadly (2004)

read original related products more articles

On Friday, we talked about some of the bad things that can happen if you call a function with the wrong signature. The ia64 introduces yet another possible bad consequence of a mismatched function signature which you may have thought was harmless.

The CreateThread function accepts a LPTHREAD_START_ROUTINE, which has the function signature

DWORD CALLBACK ThreadProc(LPVOID lpParameter);

One thing that people seem to like to do is to take a function that returns void and cast it to a LPTHREAD_START_ROUTINE. The theory is, “I don’t care what the return value is, so I may as well use a function that doesn’t have a return value. The caller will get garbage, but that’s okay; garbage is fine.” Here one web page that contains this mistake:

void MyCritSectProc(LPVOID /*nParameter*/) { ... } hMyThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) MyCritSectProc, NULL, 0, &MyThreadID);

This is hardly the only web page that supplies buggy sample code. Here’s sample code from a course at Old Dominion University that makes the same mistake, and sample code from Long Island University, It’s like shooting fish in a barrel. Just google for CreateThread LPTHREAD_START_ROUTINE and pretty much all the hits are people calling CreateThread incorrectly. Even sample code in MSDN gets this wrong. Here’s a whitepaper that misdeclares both the return value and the input parameter in a manner that will crash on Win64,

And it’s all fun until somebody gets hurt.

On the ia64, each 64-bit register is actually 65 bits. The extra bit is called “NaT” which stands for “not a thing”. The bit is set when the register does not contain a valid value. Think of it as the integer version of the floating point NaN.

The NaT bit gets set most commonly from speculative execution. There is a special form of load instruction on the ia64 which attempts to load the value from memory, but if the load fails (because the memory is paged out or the address is invalid), then instead of raising a page fault, all that happens is that NaT bit gets set, and execution continues.

All mathematical operations on NaT just produce NaT again.

... continue reading