
Hi all, I'm having some issue with boost::wave::context: I have a function called PreProcessSource, which allocates a boost::wave::context and does some preprocessing; nothing fancy at all. std::string PreProcessSource(const std::string& instring, const std::string& defines) { typedef boost::wave::cpplexer::lex_token<> token_type; typedef boost::wave::cpplexer::lex_iterator<token_type> lex_iterator_type; typedef boost::wave::context<std::string::iterator, lex_iterator_type> context_type; std::string source = instring; context_type ctx(source.begin(), source.end()); // DEADLOCK here ctx.set_language(boost::wave::enable_emit_line_directives(ctx.get_language(), true)); if(!defines.empty()) { std::vector<std::string> tokens; Split<std::string>(defines, tokens, ","); std::vector<std::string>::const_iterator cit = tokens.begin(); for (;cit != tokens.end(); ++cit) ctx.add_macro_definition(*cit); } context_type::iterator_type first = ctx.begin(); context_type::iterator_type last = ctx.end(); std::string outstring; while (first != last) { const token_type::string_type& value = (*first).get_value(); std::copy(value.begin(), value.end(), std::back_inserter(outstring)); ++first; } return outstring; } In the past it used to work fine, albeit with boost 1.47.0: Library Nitro is a DLL that hosts the PreProcess source function, the executable uses the Nitro DLL and can call PreProcess source, and Nitro DLL can also sometimes call the function itself. But right now this is no longer the case: whenever Nitro DLL calls the function itself, or Nitro DLL calls another function, which in turn calls back into Nitro DLL PreProcess function, it deadlocks. If DO_DEADLOCK is defined to 1 in the following piece of code, the deadlock will happen: // In executable class Tutorial01 : public Game { public: // ... Tutorial01() : Game() { #if !DO_DEADLOCK std::stringstream sstream; sstream << "void main(inout float4 vtxInput : POSITION) { }" << std::endl << std::endl; std::string source = sstream.str(); std::string defines = ""; std::string shaderCode = Nitro::PreProcessSource(source, defines); #endif } void LoadContent() { #if DO_DEADLOCK std::stringstream sstream; sstream << "void main(inout float4 vtxInput : POSITION) { }" << std::endl << std::endl; std::string source = sstream.str(); std::string defines = ""; std::string shaderCode = Nitro::PreProcessSource(source, defines); #endif // Original code that deadlocks too. // Calls in the DLL, which will call PreProcessSource. // effect->Initialize(device, source, "DX11"); } // ... }; int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { Tutorial00 app; app.Run(); return 0; } Note that the constructor is called directly from the executable, whereas LoadContent is called from the DLL: // In Nitro DLL void Game::Run() { try { // ... LoadContent(); // ... } catch(/* ... */) { } } The code is compiled for x64 and in debug mode. I compile boost myself into a DLL (using bcp to get the files for the libraries I use) with the following options: Preprocessor: WIN32 BOOST_ALL_NO_LIB BOOST_ALL_DYN_LINK BOOST_THREAD_BUILD_DLL _DLL _DEBUG _WINDOWS _USRDLL Code Generation: C++ Exceptions (/EHsc) Multi-threaded Debug DLL (/MDd) Function-level linking (/Gy) Streaming SIMD Extensions 2 (/arch:SSE2) (/arch:SSE2) Fast floating point model (/fp:fast) DLL A uses the same code gen options, and has the following preprocessor macros defined: _WINDLL _UNICODE UNICODE WIN32 _WINDOWS BOOST_ALL_NO_LIB _DEBUG The executable and unit test executable uses the same code gen options, and have the following preprocessor macros defined: BOOST_ALL_NO_LIB UNICODE _UNICODE _MBCS I have tried various combinations of preprocessor definitions (with _DEBUG and without, with BOOST_THREAD_USE_DLL, and without; to no avail). Here is the (cleaned up) stack trace of the deadlock: ntdll.dll!0000000076dc135a() [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] KernelBase.dll!000007fefd4f10dc() Nitro.dll!boost::call_once<void (__cdecl*)(void)>(boost::once_flag & flag, void (void)* f) Line 197 + 0x18 bytes C++ Nitro.dll!boost::call_once(void (void)* func, boost::once_flag & flag) Line 28 C++ Nitro.dll!boost::spirit::classic::static_<boost::thread_specific_ptr<boost::weak_ptr<boost::spirit::classic::impl::grammar_helper ... Line 72 + 0x13 bytes C++ Nitro.dll!boost::spirit::classic::impl::get_definition<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 241 + 0x17 bytes C++ Nitro.dll!boost::spirit::classic::impl::grammar_parser_parse<0,boost::wave::util::time_conversion::time_conversion_grammar, ... Line 296 + 0xa bytes C++ Nitro.dll!boost::spirit::classic::grammar<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 55 + 0x3c bytes C++ Nitro.dll!boost::spirit::classic::grammar<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 65 + 0x75 bytes C++ Nitro.dll!boost::spirit::classic::impl::phrase_parser<boost::spirit::classic::space_parser>::parse<char const * __ptr64,boost::wave::util::time_conversion::time_conversion_grammar> ... Line 136 C++ Nitro.dll!boost::spirit::classic::parse<char const * __ptr64,boost::wave::util::time_conversion::time_conversion_grammar, ... Line 155 + 0x3a bytes C++ Nitro.dll!boost::spirit::classic::parse<char,boost::wave::util::time_conversion::time_conversion_grammar, ... Line 173 + 0x23 bytes C++ Nitro.dll!boost::wave::util::time_conversion::time_conversion_helper::time_conversion_helper(const char * act_time) Line 123 C++ Nitro.dll!boost::wave::util::predefined_macros::predefined_macros() Line 196 + 0x38 bytes C++ ... Nitro.dll!Nitro::PreProcessSource(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & instring, const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & defines) Line 51 + 0xa0 bytes C++ Tutorial01.exe!Tutorial01::LoadContent() Line 70 + 0x33 bytes C++ Nitro.dll!Nitro::Game::Run() Line 40 C++ Tutorial01.exe!wWinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, wchar_t * lpCmdLine, int nCmdShow) Line 149 C++ Tutorial01.exe!__tmainCRTStartup() Line 547 + 0x42 bytes C Tutorial01.exe!wWinMainCRTStartup() Line 371 C kernel32.dll!00000000766a652d() ntdll.dll!0000000076d9c521() It seems boost::wave is trying to parse some time stamp, and by doing so instantiates a grammar and that's when things seem to go bad. The deadlock happens inside the constructor of the context type, and the Visual Studio debugger points me to line 197 in boost\thread\win32\once.hpp BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject( event_handle,::boost::detail::win32::infinite)); When called directly from the executable, I have noticed that the once_flag.status value is 0, and it exits the loop on the first iteration, whereas when it's called from inside the DLL, the once_flag.status value is 53, and it goes around the loop twice before falling into the WaitForSingleObject. I'm not sure if that's even relevant but I've exhausted all the possibilities and I'm out of ideas. I'd be grateful if anyone could shed some light on this. Best Regards, Julien Lebot