
| Last Modification: June 18, 2006 |
I upgraded my project to a newer version of VC++, and now I get segmentation faults in a dll that was created with another C++ compiler or VC++ version.
This is likely caused by compiler differences, and there is very little you can do about it.
Explanation
There are lot of possible problems that can occur, but there are 3 issues that are most common.
1st possible cause
The first is memory ownership. If memory is allocated inside a module, it should be de-allocated in the same module. The reason is that each module (application or dll) can have its own heap manager.
Memory that is allocated by a heap manager has to be de-allocated by the same heap manager. Failure to do so will lead to segmentation faults.
If a dll is built with a static version of the runtime, it will have its own heap manager. If a dll is built against the dynamic version of the runtime, it will use the heap manager that is available in the runtime.
If your application and the dll both use the same version of the dynamic runtime, they also use the same heap manager. In that case you would get away with de-allocating memory in the application if it was allocated inside the dll.
However, if your application is rebuilt with a newer version of VC++, it will also start using a different runtime, which will lead to problems. Note that these de-allocations can also be ‘hidden’ inside classes. For example, if a function call resizes an array inside an object that was created in another module.
As a rule, do not ever free or reallocate memory allocated by a different allocator. This covers lots of ground including CoTaskmemAlloc( the latter being an example of using a shared allocator). Also, remember that many C/C++ runtime features are dependent on the CRT allocators, and thus things like CRT file handles should not be shared across dll boundaries either if you're not using the same copy of the CRT.
2nd possible cause
The second possible cause for segmentation faults in this case could be the simple fact there is no definition of what a C++ object looks like in memory. There is no binary interface definition. Because of that, classes compiled with different C++ compilers can have a different layout in memory, or even different sizes.
This can cause all sorts of behavior. From silently corrupting data to segmentation faults.
3rd possible cause
Another possible problem is if the dll uses classes in its exported interface that are supplied with the compiler. Good examples of this are MFC classes like CString. A CString in VC++ 6 is completely different from a CString in VC++ 2005.
That means that if the application supplies a CString pointer to the dll, the dll will treat it as a VC6 CString instead of a VC2005 CString. Since they also have a different memory layout, this will most likely end in memory corruption with a segmentation fault as the end result.
The same is true for any class from which different versions exist in the dll and the application, but with classes that are supplied with the compiler it is easy to overlook.
Workaround
This problem does not have a clean solution. The only thing you can really do is to rebuild the offending dll with the same compiler version you use for the application. Note that the same problem exists for all C++ compilers. Not only Visual C++.
If you cannot do that, your only real option is to create a dll wrapper that isolates the dll from your application. For this you use the same compiler version as the one that was used for creating the original dll. You will have to provide wrapper functions for each manipulation of the original dll.
That is a lot of work. Sadly, there is no better way to solve this.
To prevent this
To prevent this problem when you are developing a dll, you have to follow a couple of simple rules:
Acknowledgements
This FAQ was contributed by Bruno van Dooren.