C++ was not originally designed to handle multi-threading. Many performance problems and application hangs can be traced back to thread management routines in your unmanaged code. Fortunately, Application Verifier includes a component called Lock Verifier (also known as the Critical Section Verifier) that checks for common problems that occur when you implement critical sections. In turn, you can troubleshoot and correct the problem from the source.
Critical sections are essential in managing resources in a multi-threaded execution environment. Imagine several applications trying to access the same code block without any management or locking mechanism. You would experience all kinds of problems, including leaks and access violations. For example, thread A might change the value of an operand to zero. Thread B would then be able to change it to some other value. Chaos would ensue.
The locks component of Application Verifier is designed to dynamically monitor all the critical sections in your code. Common errors include repeatedly initializing the same critical section or deleting it multiple times. You can avoid problems by making sure that your threads management is properly sequenced with your memory management. Another common problem that occurs is improperly matching each EnterCriticalSection with a corresponding LeaveCriticalSection.
The following list describes the stop codes generated by Application Verifier, with extra explanations and fixes to help you troubleshoot the problems in your code:
Critical section over-released or corrupted: If a critical section is released more times than it is acquired, you may encounter this stop code.
For example, if you call DeleteCriticalSection and then try to reference the critical section object you deleted (by making calls such as LeaveCriticalSection), you run the risk of memory corruption and other problems.
Also watch out for the number of EnterCriticalSection and LeaveCriticalSection calls in your code. For each EnterCriticalSection call, there should be a corresponding LeaveCriticalSection call.
The thread cannot own a lock in this context: When a thread is terminated, suspended, or exited, it can no longer own a critical section. This stop code will occur when the thread is in one of these states while owning an active critical section.
To troubleshoot this problem, look at your current thread and avoid calling ExitThread, SuspendThread, or TerminateThread without first exiting or deleting your critical section.
Module contains an active lock: This stop is generated if a DLL has a global variable containing a lock and the DLL is unloaded but the critical section has not been deleted. The name of the module that has an active lock is shown in the error message. The Tool Window displays the stack trace for the critical section initialization. Also, check the contents of the current call stack when the DLL with the active lock was unloaded.
The Lock has already been initialized or The lock has been double initialized: You will likely get one of these stop codes when a critical section has been initialized repeatedly or the structure of the critical section is corrupted. The net effect on your application is that it will start behaving abnormally. To troubleshoot this problem, count all your initialization/exiting calls in the call stack for orphans. You can then use the stack trace to look at the first initialization. Keep in mind that this bug can cause critical section corruption, which may provide inaccurate debug information. In those instances, the stack trace may be inaccurate.
Released virtual memory containing an active lock: This stop is generated if the current thread is calling VirtualFree on a memory block that contains an active critical section. The application should call DeleteCriticalSection on this critical section before if frees this memory.
Released memory containing an active lock: This stop code is very similar to "Released virtual memory containing an active lock" in that your application is trying to free heap memory that contains a critical section.
Application Verifier detects this problem using the DebugInfo field; if it is pointing to a block of memory that has been freed, a break is called.
You must first call DeleteCriticalSection before releasing memory.
The lock is corrupted: This stop normally occurs if the DebugInfo field of the critical section is pointing to freed memory. Another valid DebugInfo structure is found in the active critical section list. Without corruption the two pointers should be identical. You should dump the memory location that is trying to be accessed by the critical section for corruption patterns.
The lock count is invalid: The LockCount field indicates whether a critical section is held within the current context. The default value is -1. If it has a value of 0 or more, the critical section is held, and the OwningThread field will store the corresponding thread ID.
If the owner is zero, then the critical section is being deleted without initializing. If it is not zero, it is being deleted while a thread still owns the critical section (e.g., LeaveCriticalSection has not been called).
The lock has been over released: If you close the same lock or critical section more than once, you will encounter this stop code. You should verify the stack trace to pinpoint the source of the problem and remove any duplicate exiting routines such as LeaveCriticalSection. This is a very common error.
The owner of the lock is invalid, owner was expected: This stop is generated if the owner thread ID is invalid in the current context. Check the contents of the current call stack where the thread calls EnterCriticalSection or LeaveCriticalSection. Examine the call stacks of the current owning thread and the expected owner thread.
The recursion count is invalid: The recursion count field in a critical section monitors the number of times a thread acquires a lock using EnterCriticalSection or TryEnterCriticalSection. If the field is invalid in the current context, you will get this stop code. The default value for the field is 0, and will increment whenever the thread enters a new critical section. To troubleshoot, look at the call stack for instances of a thread calling LeaveCriticalSection more frequently than EnterCriticalSection.
Thread not supposed to be owning a lock: Whenever a thread enters a critical section, it is noted. If a thread tries a LeaveCriticalSection call without owning the critical section, then this stop code will be raised.
To avoid this problem, make sure that your lock count is correct. For every EnterCriticalSection, there should be a corresponding LeaveCriticalSection. Many lock errors occur as a result of a mismatch between EnterCriticalSection and LeaveCriticalSection calls.
The lock is being used without having been initialized: If you try to use a critical section without initializing it or after you have exited it, you will receive this stop code. A careful code review will usually help you nail the source of the problem (you can start by looking at the call stack to find out where the lock is being used before it is initialized).
The region of memory about to be freed contains an active lock: This stop is generated if the memory containing a critical section was freed but the critical section has not been deleted using DeleteCriticalSection. Typically, this stop will occur if a previous stop happens to "continue"—for example, if you encountered the "Memory location at <address> contains an active lock" stop and then choose to continue running your code. In most cases, the lock verifier immediately detects leaked critical sections contained in a heap allocation, a DLL range, a virtual memory allocation, or a MapViewOfFile mapped memory range. It then issues different stops in each of these cases.
For great information on concurrency, thread management, and creating Windows applications with high availability, please visit Larry Osterman's blog at http://www.blogs.msdn.com/larryosterman/.