Date: | September 22, 2017 / year-entry #213 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20170922-00/?p=97065 |
Comments: | 6 |
Summary: | It probably means that you're entering a critical section that is not initialized. |
Warning: This article talks about implementation details which can change at any time. The information provided is for debugging and diagnostic purposes only.
A customer found that
their server program occasionally crashes in the internal function
7789dde3 ff4014 inc dword ptr [eax+14h]
The dereference was due to a null pointer in the
The customer chased the null pointer backwards and found that it
came from the typedef struct _RTL_CRITICAL_SECTION { // value in memory: PRTL_CRITICAL_SECTION_DEBUG DebugInfo; // 0x00000000 LONG LockCount; // 0xFFFFFFFC LONG RecursionCount; // 0x00000000 PVOID OwningThread; // 0x00000000 PVOID LockSemaphore; // 0x00005CDC ULONG SpinCount; // 0x00000000 } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
The customer confirmed that, yes,
the
Although the customer didn't do it in their application
(at least not knowingly),
they did try a test application which passed the
Is it possible that this is a critical section that was initialized
with the traditional
No, that's not why the the
So what does it mean when the
Other evidence that you have an uninitialized critical section is that the critical section is locked, yet has no owner. Furthermore, the spin count is zero, which occurs only on uniprocessor systems. I suspect the server they are running the program on has more than one core. (Heck, my phone has more than one core.) Bonus reading: Displaying a critical section in the debugger. Related: I hope you werent using those undocumented critical section fields. |
Comments (6)
Comments are closed. |
Well, without knowing the internals of a critical section and just by reading the article’s title (not even the subtitle), my psychic powers told me it was due to a null pointer, possibly because they were accessing an uninitialized critical section, or maybe because of memory corruption. Anyway, debugging is necessary to find the final cause. But if it only happens after running for a week, good luck with that. Another of those fun bugs where you end up reading code in hope of finding something that could cause the observed problem (and you fix some unrelated bugs in the way).
The physical hardware they were running on was *vanishingly* unlikely to be uniprocessor – but the VM they were running in might have been.
I suspect a *lot* of servers these days are running inside VMs – and if you don’t need multi-threaded throughput, a uniprocessor machine eliminates quite a lot of potential problems.
That depends on the meaning of “uniprocessor systems”. Its been a while since we had special uniprocessor kernel builds. A modern system might support hot swappable CPUs so the core count is not fixed at boot.
I discovered a long time ago the uniprocessor kernel has a deadlock bug the multiprocessor bug doesn’t. If you try to read a handle from one thread and close it from another it will deadlock until the read finishes (which could be never). The multiprocessor kernel won’t deadlock on this.
Basically, uniprocessor kernels make a good number of optimizations based on the fact that there are only a processor, and thus, you can make some assumptions, like “read-modify-store instructions are always atomic”, or “there can’t be race conditions without context switches”. This allows you to save some instructions, and in some cases, even avoid switching to/from kernel mode. Which improves performance. But, as with every optimization, you risk introducing new bugs.
Anyway, the Windows kernel should be the most tested piece of software of history. Are you sure it really was a bug, and not a side effect of some documented behavior?
If you can get a thread into an uninterruptible sleep it’s a security bug. I don’t remember trying terminate process to try to unwedge it but that thread was stuck in kernel.