views:

315

answers:

2

I have encountered an unexpected Access Error while running a project I've built using two different versions of Visual Studio. My general configuration is as follows:

  • LibA is a static lib, static runtime linkage, msvc 8.0
  • LibB is a static lib, static runtime linkage, msvc 9.0
  • My target project for integration is a msvc 9.0 COM dll, which statically links the above libraries

This project builds, but crashes up at runtime with an access violation in some STL code. The stack seems to indicate that I've passed through headers both versions (8 and 9) during a call into a stream insertion operator. I realize that this is a problem.

Somehow, this call:

ost << std::dec << port_; //(originating from an object in LibA)

...descends through the following stack trace:

std::basic_ostream::operator<<(...) (ostream:283, msvc 8.0 version <-- expected, since LibA was built with this version)
std::num_put::put(...) (xlocnum:888, msvc 8.0 version <-- expected, since LibA was built with this version)
std::num_put::do_put(...) (xlocnum:1158, msvc 9.0 version!! !@#$!%! <-- not expected, since LibA was built with msvc 8.0)
std::ios_base::flags() (xiosbase:374, msvc 9.0 version <-- follows from above)

The access violation happens in std::ios_base::flags(). I suspect it is due to the mix of implementations in the call stack (although I am not sure).

My questions are.

1.) Is the likely cause of this access violation the mixing of msvc header implementations?
2.) Is there a way to prevent these implementations from mixing?
3.) Is there a better way to configure these three projects for integration (assuming moving LibA from msvc 8.0 is undesirable)?

I am aware of the ideas raised in this question and this one. Here I am most interested in this specific problem, and if there is some way to avoid it.

Any insights would be appreciated.

+2  A: 

You can't use different STL implementation in the same project. This means even different versions from the same compiler. If your LibA has a function that accepts std::vector as an argument you are only allowed to pass vector object from STL that LibA was built with. This is why many C++ libraries expose only C API.

Either you change your API or you rebuild all your projects using the same compiler.

You are doing something that you shouldn't. You are in the world of undefined behavior. There is no point in trying to debug this particular crash. Even if you managed to make this line work you would get a new crash somewhere else.

Nikola Smiljanić
With this specific problem, I'm not even to the point of passing data between libraries. This is a call into operator<< originating from LibA, but somehow it's descending into a different headers than it was compiled with.
Adam
@Adam: The debugger may be lying about which header you're stepping into (because it's confused). Or it may not matter because the linker chose between two identical implementations. Nikola is right. You're in undefined territory. You need to fix the build rather than debug the symptom.
Adrian McCarthy
@Adrian: I had considered the possibility that the debugger was misleading, but I decided that the debug symbols likely had the full path included (thus the debugger distinguished between the two versions of the header "xlocnum" in the same call stack).I also agree that this is undefined territory. I was interested to learn if there is a way to prevent this unintentional mixing withing the same call stack. It's starting to sound like the answer is 'no'.
Adam
@Adam: Here is a possible explanation for your call stack http://stackoverflow.com/questions/1948204
Nikola Smiljanić
+1  A: 

There is no guarantee of library binary compatibility between major versions of MSVC. STL code is mostly template code that gets expanded into your code. So you're static libraries probably have incompatible chunks of STL code inside of them.

In general, this shouldn't be a problem, unless that STL code is part of the interface to the library. For example, if you pass iterators or a reference to a vector from one library to another, you're in trouble.

The best solution is to build everything with the same version of the compiler. If you can't do that (e.g., if the one of the libraries is from a third-party), you're probably stuck.

Adrian McCarthy