views:

728

answers:

7

I'm trying to use boost::signal to implement a callback mechanism, and I'm getting a memory access assert in the boost::signal code on even the most trivial usage of the library. I have simplified it down to this code:

#include <boost/signal.hpp>

typedef boost::signal<void (void)> Event;

int main(int argc, char* argv[])
{

    Event e;

    return 0;
}

Thanks!

Edit: This was Boost 1.36.0 compiled with Visual Studio 2008 w/ SP1. Boost::filesystem, like boost::signal also has a library that must be linked in, and it seems to work fine. All the other boost libraries I use are headers-only, I believe.

+1  A: 

I've tested your code on my system, and it works fine. I think that there's a mismatch between your compiler, and the compiler that your Boost.Signals library is built on. Try to download the Boost source, and compile Boost.Signals using the same compiler as you use for building your code.

Just for my info, what compiler (and version) are you using?

Chris Jester-Young
A: 

@Chris - Thanks for testing it. I will look to see if something went wrong when I built the boost library... What version and compiler did you test with?

Brian Stewart
I tested with Boost 1.34 (since that's the version that comes with Ubuntu 8.04), 64-bit, GCC 4.2.3.
Chris Jester-Young
+1  A: 

Works for me too. VS 2008 SP1, boost 1.36.

Roel
Yay! Then I don't have to download VS2008 SP1 just to test it myself. :-)
Chris Jester-Young
+1  A: 

This kind of problem often occurs when compiling with a different heap implementation. In VS, it is possible to ask for the CRT to be linked in (as a static library), or left as a dynamic library.

If the library you use allocates memory on its linked-in heap, and your program tries to deallocate it, using another heap, you get in trouble: the object to be freed is not on the list of objects that were allocated.

xtofl
+1  A: 

@xtofl - Thanks for the tip. you are right, that would cause this type of problem - but I was building everything /MDd here.

It turns out the simple example I included in the question was still being built using our build system, which uses inherited property sheets to set a number of different compiler and linker flags. I have managed to duplicate this behavior in a really vanilla VS 2008 project, without any of our build stuff, by setting the compiler flags _SECURE_SCL=0 and _HAS_ITERATOR_DEBUGGING=0. When I remove these flags, boost::signal works fine. It makes perfect sense now that these flags would need to be set while compiling boost - I just didn't think about it for some reason. And we haven't had any problems with the only boost lib we have used this far (boost::filesystem). So I guess I need to find a way to build boost with these flags set. Thanks everybody.

Brian Stewart
+5  A: 

I have confirmed this as a problem - Stephan T Lavavej (STL!) at Microsoft blogged about this.

Specifically, he said:

The general problem is that the linker does not diagnose all One Definition Rule (ODR) violations. Although not impossible, this is a difficult problem to solve, which is why the Standard specifically permits certain ODR violations to go undiagnosed.

I would certainly love for the compiler and linker to have a special mode that would catch all ODR violations at build time, but I recognize that that would be difficult to achieve (and would consume resources that could perhaps be put to even better use, like more conformance). In any event, ODR violations can be avoided without extreme effort by properly structuring your code, so we as programmers can cope with this lack of linker checking.

However, macros that change the functionality of code by being switched on and off are flirting dangerously with the ODR, and the specific problem is that _SECURE_SCL and _HAS_ITERATOR_DEBUGGING both do exactly this. At first glance, this might not seem so bad, since you should already have control over which macros are defined project-wide in your build system. However, separately compiled libraries complicate things - if you've built (for example) Boost with _SECURE_SCL on, which is the default, your project must not turn _SECURE_SCL off. If you're intent on turning _SECURE_SCL off in your project, now you have to re-build Boost accordingly. And depending on the separately compiled library in question, that might be difficult (with Boost, according to my understanding, it can be done, I've just never figured out how).

He lists some possible workarounds later on in a comment, but none looked appropriate to this situation. Someone else reported being able to turn off these flags when compiling boost by inserting some defines in boost/config/compiler/visualc.hpp, but this did NOT work for me. However inserting the following line VERBATIM in tools/build/v2/user-config.jam did the trick. Note that the whitespace is important to boost jam.

using msvc : 9.0 : : <cxxflags>-D _SECURE_SCL=0 <cxxflags>-D _HAS_ITERATOR_DEBUGGING=0 ;
Brian Stewart
A: 

Brian, I've just experienced exactly the same problem as you. Thanks to your answer about the blog post, I tracked it down to our disabling of _HAS_ITERATOR_DEBUGGING and _SECURE_SCL.

To fix this problem, I built the boost libraries manually. I didn't need to mess around with config files. Here are the two command lines I used:

x86
bjam debug release link=static threading=multi runtime-link=shared define=_SECURE_SCL=0 define=_HAS_ITERATOR_DEBUGGING=0 --with-signals stage

x64
bjam debug release link=static threading=multi runtime-link=shared define=_SECURE_SCL=0 define=_HAS_ITERATOR_DEBUGGING=0 address-model=64 --with-signals stage

This builds the following files:
libboost_signals-vc90-mt-1_43.lib
libboost_signals-vc90-mt-gd-1_43.lib

Hope that helps.

Mark Ingram