Article ID: 813810
When you build applications in Microsoft Visual C++ 6.0 that use the supplied Standard Template Library (STL), memory corruption may occur, or your computer may stop responding. These symptoms occur more frequently on multi-processor computers. Previously, the same code may have worked without such issues on a single-processor computer. When you examine the faulting thread in a debugger, you typically see the failure in a memory management function. Frequently you see the basic_string<char...> class methods in the stack trace. Because memory corruption is also a symptom, failures may appear in areas that are unrelated to string processing.
The following are examples of stack traces where this problem was the cause of a crash:
The Standard Template Library (STL) that is included with Microsoft Visual C++ 6.0 is not safe for multi-threaded applications. In particular, the implementations of the std::string class depend on the basic_string<...> template class. The basic_string<...> template class reference counts copies of a hidden character buffer. The basic_string<...> template class stores the count in an 8-bit unsigned char. The following general issues occur after this implementation:
You must rebuild the application after you make the STL thread-safe. The preferred method to obtain a thread-safe STL is to upgrade the STL to a newer version that is based on the current Visual C++ standard. However, the STL that is based on the current Visual C++ standard is not identical to the STL that was available at the time that Microsoft Visual C++ 6.0 was released as a new product. However, upgrading to a new version may be trivial depending on the STL functions that your application uses. To obtain new versions of the thread-safe STL, use one of the following methods:
Method 1: Use Microsoft Visual C++ .NET (versions 7.0 and later)Open each Visual C++ project in your application, allow the project to automatically convert to the new project format, and then rebuild it. The std::string class implementation in this version is thread-safe for the described problem. If you use the DLL run-time library feature in your any one of the projects in your application, you must distribute the new Visual C++ run-time components (such as Msvci7x.dll, Msvcp7x.dll, and Msvcr7x.dll) with your rebuilt application.
Note You do not have to distribute the Microsoft .NET Framework to client computers to use Microsoft Visual C++ .NET.
Method 2: Use Microsoft Visual C++ 6.0 with a replacement STL from a third partyThe details of integration vary by product, and the individual vendors provide support. One source for a successor STL version is Dinkumware, Ltd., the company where Microsoft licenses the Visual C++ 6.0 STL. It is claimed that it can integrate with existing build processes. For more information, and for a list of known bugs and workarounds, visit the following Dinkumware Web site:
www.dinkumware.comMicrosoft provides third-party contact information to help you find technical support. This contact information may change without notice. Microsoft does not guarantee the accuracy of this third-party contact information. The third-party products that this article discusses are manufactured by companies that are independent of Microsoft. Microsoft makes no warranty, implied or otherwise, regarding the performance or reliability of these products.
Work around the std::string class issue in Microsoft Visual C++ 6.0 STLIf you do not upgrade to a new version of the STL, you can try to correct the std::string class thread-safety issue in the standard Microsoft Visual C++ 6.0 installation. Although there are multi-threading issues with several of the classes in the Microsoft Visual C++ 6.0 STL, by far the most common and problematic class is the std::string class. The following steps and workarounds are stopgap measures to make sure that an application is working correctly, and the measures provide time to investigate other alternatives. Consider that these instructions will create new code paths and behavior perhaps throughout your whole application. Thoroughly test the rebuilt application in accordance with a company's or an individual's software policies before widespread deployment.
Disable string reference countingEach of the workarounds that is documented in this section require that you first disable the reference-count mechanism. To disable reference counting, you must modify the <xstring> header file and set the _FROZEN enumeration constant to 0. In default installations, the <xstring> header file is in the following location:
C:\Program files\Microsoft Visual Studio\VC98\IncludeChange the _FROZEN enumeration constant to 0 in the <xstring> header file at line 62 so that it looks similar to the following:
If you follow this recommendation, and you rebuild all software that uses these header files, your std::string class code will be more thread-safe. There are some caveats to that statement. Therefore, read the following workaround instructions carefully. After you disable reference counting by setting the _FROZEN enumeration constant to 0 in the <xstring> header file, use one of the following methods to work around this problem.
Method 1: Use static CRT linkage onlyModify the project settings in all your projects that use the std::string class to link to the static version of the Microsoft run-time library (CRT). You cannot use this approach if your project also has the Use MFC in a Shared DLL setting enabled. For each project, follow these steps:
Method 2: Use dynamic CRT linkageIf your project code must link to the runtime library (CRT) as a DLL, you must take a different approach. Dynamic CRT linkage is the default setting for DLL projects. Dependencies on other components such as MFC or third-party libraries that are licensed for use with your application, typically require dynamic linkage to the CRT. If your only dependency is MFC, you can use the Use MFC in a Static Library option, and apply Method 1. By default, when you create a new project in Microsoft Visual C++ 6.0, the project uses the CRT from a DLL.
The dynamic CRT linkage project setting links your application to implementations for some std::string class methods in the pre-built Microsoft CRT DLL that is named Msvcp60.dll. Because Microsoft built that DLL by using the unmodified <xstring> header file, the change to the _FROZEN constant that you made to the local copy of <xstring> is not honored for functions that are called out of that library. These include functions such as _Tidy(), and assign() that are supplied in the Msvcp60.dll file for the <char> and <short> instantiations of the basic_string class. The basic_string class is the base for the std::string class.
To use static implementations of the std::string class in your modules instead of the Microsoft-supplied implementations in the Msvcp60.dll file, follow these steps:
Method 3: Using a clever hack to avoid linkage issuesCreate a typedef for unsigned char, and use that instead of the existing std::string class typedef. The typedef may take a form that is included in a header file in the source files of the application that use the std::string class. The typedef may appear similar to the following:
Any string literals that are used with this class must be cast or processed as unsigned char. There may be an increase in code size versus ease of implementation, and there are less linkage side effects.
Method 4: Using a custom std::string DLLThis option gains you the benefit of smallest code size by putting the std::string class implementations in a single DLL. Create a DLL project that exports the std::string class. Link to that DLL instead of to the standard Msvcp60.dll file. You must redistribute this new DLL together with your application. This is an advanced option.
The following C++ code examples demonstrate one scenario that may occur when there is a lack of synchronization:
In this example, Thread1 makes a copy of the input argument, and raises the reference count on the shared character buffer to 1. While it is working, Thread2 also makes a copy of its input argument, and raises the reference count to 2. Meanwhile, the main thread assigns a new value to A, creates a new character buffer, and drops the reference count on the original shared buffer to 1.
Thread1 starts to create a new character buffer for the new assignment to A1, recognizes a positive reference count on its previous shared character buffer, and then decrements that count by 1 to 0. At the same time, Thread2 is also in the process of assignment to B. B shares the character buffer of A2, and raises the reference count on the character buffer of A2, trying to increment it to 2 just before Thread1 writes a 0 to the reference count. The reference count is now 0 instead of 1. The reference count would have been 0 if access to the reference counter had been synchronized.
When Thread2 assigns a new value to A2, Thread2 sees the reference count of 0 and discards the original shared character buffer that B still references. The memory that held the character buffer is now available for other uses in the application. However, std::string B still holds a pointer to the character buffer. The following scenarios cause corruption and crashes:
For more information about Visual C++ language and compiler issues, see the Is the STL included with VC++ thread-safe? topic at the following Microsoft Most Valuable Professional (MVP) Web site:
Article ID: 813810 - Last Review: June 20, 2014 - Revision: 2.0