The complete code is more than 400 line. You can find it here: http://hostcode.sourceforge.net/view/4122 or if you have wxwidgets installed then under WX_WIDGETS_ROOT\samples\wizard\wizard.cpp.
I tried to compile it but get
"error C2065: 'm_bitmap' : undeclared identifier" on line 122.
Then I commented that line and it compiles ok. But when I run it and select one of these menu commands:
File >> Run wizard modal
File >> Run wizard withour sizer
File >>
Run wizard modeless
it goes to MyWizard constructor and crashes on m_page1 = new... line.
MyWizard::MyWizard(wxFrame *frame, bool useSizer)
: wxWizard(frame,wxID_ANY,_T("Absolutely Useless Wizard"),
wxBitmap(wiztest_xpm),wxDefaultPosition,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
// a wizard page may be either an object of predefined class
m_page1 = new wxWizardPageSimple(this);<---------------- HERE
and gave this error:
Unhandled exception at 0x004425ec in wizard.exe: 0xC0000005: Access
violation reading location 0xcdcdcdd1.
I checked in debugger and saw that it goes to
void wxWizardPage::Init()
{
m_bitmap = wxNullBitmap;<--- HERE
}
and then a few inner calls later trying to access m_refData->m_count where m_refData contains garbage m_refData = 0xcdcdcdcd {m_count=??? } and then crashed.
void wxObject::UnRef()
{
if ( m_refData )
{
wxASSERT_MSG( m_refData->m_count > 0, _T("invalid ref data count") );<----- HERE
if ( --m_refData->m_count == 0 )
delete m_refData;
m_refData = NULL;
}
}
Here is call stack if it will be useful:
wizard.exe!wxObject::UnRef() Line 346 + 0x6 bytes C++
wizard.exe!wxObject::Ref(const wxObject & clone) Line 335 C++
wizard.exe!wxObject::operator=(const wxObject & other) Line 428 C++
wizard.exe!wxGDIObject::operator=(const wxGDIObject & __that) + 0x13
bytes C++ wizard.exe!wxGDIImage::operator=(const wxGDIImage &
__that) + 0x13 bytes C++ wizard.exe!wxBitmap::operator=(const wxBitmap & __that) + 0x13 bytes C++
wizard.exe!wxWizardPage::Init() Line 126 C++ wizard.exe!wxWizardPage::wxWizardPage() Line 50 + 0x46 bytes C++
wizard.exe!wxWizardPageSimple::wxWizardPageSimple(wxWizard * parent,
wxWizardPage * prev, wxWizardPage * next, const wxBitmap & bitmap,
const char * resource) Line 113 + 0x2e bytes C++
wizard.exe!MyWizard::MyWizard(wxFrame * frame, bool useSizer) Line
376 + 0x31 bytes C++
Related
I am trying to use Azure storage sdk C++ library with Unreal Engine 4 to upload images to the Azure cloud. Library is built with vcpkg and dlls are linked dynamically. Here is a simplified example of the code I use.
THIRD_PARTY_INCLUDES_START
#pragma warning(disable:4668)
#pragma warning(disable:4005) // 'TEXT': macro redefinition
#include <was/storage_account.h>
#include <was/blob.h>
#include <cpprest/filestream.h>
#include <cpprest/containerstream.h>
THIRD_PARTY_INCLUDES_END
const utility::string_t storage_connection_string(U("DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=MyAccountKey;EndpointSuffix=core.windows.net"));
void AAwsTest2GameModeBase::StartPlay() {
try
{
// Retrieve storage account from connection string.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the blob client.
azure::storage::cloud_blob_client blob_client = storage_account.create_cloud_blob_client();
// Retrieve a reference to a container.
azure::storage::cloud_blob_container container = blob_client.get_container_reference(U("image-container"));
azure::storage::cloud_block_blob blockBlob = container.get_block_blob_reference(U("28bbcdb0b3e5417b207572e292ae98412cd9d931eae6266f7c4fd788ad8544a20.jpg"));
concurrency::streams::istream input_stream = concurrency::streams::file_stream<uint8_t>::open_istream(U("image.jpg")).get();
blockBlob.upload_from_stream(input_stream);
input_stream.close().wait();
}
catch (const std::exception& e)
{
std::wcout << U("Error: ") << e.what() << std::endl;
}
}
Build.cs content
public class Program : ModuleRules
{
public Program(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
//I tried to use ansi allocator but it did not help
//PublicDefinitions.Add("FORCE_ANSI_ALLOCATOR");
PublicIncludePaths.Add(Path.Combine(DependencyFolderWin, "include"));
PublicAdditionalLibraries.Add(Path.Combine(DependencyFolderWin, "lib", "wastorage.lib"));
PublicAdditionalLibraries.Add(Path.Combine(DependencyFolderWin, "lib", "cpprest_2_10.lib"));
PublicAdditionalLibraries.Add(Path.Combine(DependencyFolderWin, "lib", "brotlicommon.lib"));
PublicAdditionalLibraries.Add(Path.Combine(DependencyFolderWin, "lib", "brotlidec.lib"));
PublicAdditionalLibraries.Add(Path.Combine(DependencyFolderWin, "lib", "brotlienc.lib"));
PublicAdditionalLibraries.Add(Path.Combine(DependencyFolderWin, "lib", "zlib.lib"));
}
private string DependencyFolderWin
{
get
{
string moduleDir = Path.GetFullPath(ModuleDirectory);
return Path.Combine(moduleDir, "./../../deps");
}
}
}
The problem is that it successfully uploads image and crashes right after return from this function (in this case StartPlay() or Upload() as in the callstack) with this callstack:
UE4Editor-Core.dll!00007ff9e620ff1b() Unknown
UE4Editor-Core.dll!00007ff9e62109e3() Unknown
UE4Editor-Core.dll!00007ff9e6211592() Unknown
UE4Editor-Core.dll!00007ff9e5e95277() Unknown
[Inline Frame] UE4Editor-MsgQueuePlugin.dll!operator delete(void *) Line 31 C++
[Inline Frame] UE4Editor-MsgQueuePlugin.dll!std::_Deallocate(void * _Ptr, unsigned __int64 _Bytes) Line 207 C++
[Inline Frame] UE4Editor-MsgQueuePlugin.dll!std::allocator<wchar_t>::deallocate(wchar_t * const) Line 992 C++
UE4Editor-MsgQueuePlugin.dll!std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >::_Tidy_deallocate() Line 3992 C++
[Inline Frame] UE4Editor-MsgQueuePlugin.dll!std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >::{dtor}() Line 2460 C++
UE4Editor-MsgQueuePlugin.dll!web::uri::~uri() C++
UE4Editor-MsgQueuePlugin.dll!azure::storage::cloud_blob::~cloud_blob() C++
UE4Editor-MsgQueuePlugin.dll!AzureUploader::Upload(TArray<unsigned char,FDefaultAllocator> file, const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & path, const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & fileName) Line 37 C++
Callstack with Editor debug symbols:
[Inline Frame] UE4Editor-Core.dll!__TBB_machine_cmpswp1(volatile void *) Line 69 C++
[Inline Frame] UE4Editor-Core.dll!__TBB_TryLockByte(unsigned char &) Line 917 C++
UE4Editor-Core.dll!__TBB_LockByte(unsigned char & flag) Line 924 C++
[Inline Frame] UE4Editor-Core.dll!MallocMutex::scoped_lock::{ctor}(MallocMutex &) Line 66 C++
UE4Editor-Core.dll!rml::internal::Block::freePublicObject(rml::internal::FreeObject * objectToFree) Line 1382 C++
[Inline Frame] UE4Editor-Core.dll!rml::internal::internalPoolFree(rml::internal::MemoryPool * memPool, void *) Line 2571 C++
UE4Editor-Core.dll!rml::internal::internalFree(void * object) Line 2595 C++
UE4Editor-Core.dll!FMemory::Free(void * Original) Line 76 C++
[External Code]
UE4Editor-MsgQueuePlugin.dll!AzureUploader::Upload(TArray<unsigned char,FDefaultAllocator> file, const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & path, const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & fileName) Line 37 C++
Looks like it crashes while deleting uri from some structure. Probably, the problem is with unreal memory management. I tried to use ansi allocator but it did not help. Any ideas how to make it work properly?
Thank you
Finally, it was solved by using UE4 plugin from this example. It is not the solution I wanted but at least it works. There are statically linked libraries and hardcoded compiler version which may bring problems in the future.
I can't seem to figure out something getting V8 started up. I have this code:
if (!_V8Initialized)
{
v8::V8::InitializeICU();
v8::V8::InitializeExternalStartupData("x86\\"); // (this loads ok, I checked)
auto platform = v8::platform::CreateDefaultPlatform();
v8::V8::InitializePlatform(platform);
v8::V8::Initialize();
_V8Initialized = true;
}
auto params = Isolate::CreateParams();
params.array_buffer_allocator = ArrayBuffer::Allocator::NewDefaultAllocator();
_Isolate = Isolate::New(params);
But I get this error:
Exception thrown at 0x0000000000000000 in V8.Net.Console.exe:
0xC0000005: Access violation executing location 0x0000000000000000.
v8_libbase.dll!v8::base::OS::Abort() Line 832 C++
v8_libbase.dll!V8_Fatal(const char * file, int line, const char * format, ...) Line 74 C++
v8.dll!v8::internal::SnapshotData::SnapshotData(const v8::internal::Vector snapshot) Line 28 C++
v8.dll!v8::internal::Snapshot::Initialize(v8::internal::Isolate * isolate) Line 43 C++
v8.dll!v8::Isolate::New(const v8::Isolate::CreateParams & params) Line 8237 C++
V8_Net_Proxy_x64.dll!V8EngineProxy::V8EngineProxy(bool enableDebugging, void()() debugMessageDispatcher, int debugPort) Line 89 C++
V8_Net_Proxy_x64.dll!CreateV8EngineProxy(bool enableDebugging, void()() debugMessageDispatcher, int debugPort) Line 19 C++
[Managed to Native Transition]
V8.Net.dll!V8.Net.V8Engine.V8Engine() Line 246 C#
V8.Net.Console.exe!V8.Net.Program.Main(string[] args) Line 31 C#
[Native to Managed Transition]
mscoreei.dll!00007ffdbdd281ad() Unknown
mscoree.dll!00007ffdbddc10ab() Unknown
kernel32.dll!00007ffdd3868364() Unknown
ntdll.dll!00007ffdd5ef70d1() Unknown
It seems to be failing here:
explicit SnapshotData(const Vector<const byte> snapshot)
: SerializedData(const_cast<byte*>(snapshot.begin()), snapshot.length()) {
CHECK(IsSane()); <-- THIS FAILS
}
I followed the source code here (for the most part): https://chromium.googlesource.com/v8/v8/+/branch-heads/4.8/samples/hello-world.cc
... but I'm not sure why it seems I'm getting a null error. I must be missing something...
Nevermind, I always seem to figure things out AFTER posting to SO, lol. It turns out I was loading from the x86 directory and not the x64 directory (which I should have guess given the V8_Net_Proxy_x64.dll! lol).
I was going to delete the question, but I'll leave this here anyhow in case someone else falls into this in the middle of the night half asleep. ;)
I'm trying to load 3D objects using Assimp built with VS2008. The Assimp example code loads the object correctly until I define (but don't instantiate) a mesh class to handle the object data in my build. Specifically, the error occurs when I include code to check the size of a vector. This problem occurs regardless of whether I use the noboost version of Assimp. I've tried several different .obj files with the same result.
Using the debugger, I've found that the Assimp loader fails when reading the faces of an .obj file. This happens on line 317 of Assimp's ObjFileParser.cpp:
pIndices->push_back( iVal-1 );
Mesh.cpp (this class is not instantiated or used as a predeclaration in main.cpp)
#pragma once
#include <vector>
class Mesh
{
void Init(const std::vector<unsigned int>& Indices){ Indices.size(); }
^^^^^^^^^^^^^^^
};
main.cpp
#include <assimp/Importer.hpp> // C++ importer interface
#include <assimp/scene.h> // Output data structure
#include <assimp/postprocess.h> // Post processing flags
bool DoTheImportThing( const std::string& pFile)
{
// Create an instance of the Importer class
Assimp::Importer importer;
// And have it read the given file with some example postprocessing
// Usually - if speed is not the most important aspect for you - you'll
// propably to request more postprocessing than we do in this example.
const aiScene* scene = importer.ReadFile( pFile,
aiProcess_CalcTangentSpace |
aiProcess_Triangulate |
aiProcess_JoinIdenticalVertices |
aiProcess_SortByPType);
// If the import failed, report it
if( !scene)
{
//DoTheErrorLogging( importer.GetErrorString());
const char* err = importer.GetErrorString();
return false;
}
// Now we can access the file's contents.
//DoTheSceneProcessing( scene);
// We're done. Everything will be cleaned up by the importer destructor
return true;
}
int main()
{
DoTheImportThing("floor.obj");
}
The std::bad_alloc at memory location exception is thrown in mlock.c
void __cdecl _unlock (
int locknum
)
{
/*
* leave the critical section.
*/
LeaveCriticalSection( _locktable[locknum].lock );
}
My call stack is
KernelBase.dll!7512c41f()
[Frames below may be incorrect and/or missing, no symbols loaded for KernelBase.dll]
KernelBase.dll!7512c41f()
ntdll.dll!7746107b()
> msvcr90d.dll!_unlock(int locknum=8) Line 376 C
msvcr90d.dll!_unlockexit() Line 808 + 0x7 bytes C
msvcr90d.dll!_CxxThrowException(void * pExceptionObject=0x0110d644, const _s__ThrowInfo * pThrowInfo=0x54655f68) Line 161 C++
msvcr90d.dll!operator new(unsigned int size=842150452) Line 64 C++
AssimpLoadFileTest.exe!std::_Allocate<unsigned int>(unsigned int _Count=210537613, unsigned int * __formal=0x00000000) Line 43 + 0xc bytes C++
AssimpLoadFileTest.exe!std::allocator<unsigned int>::allocate(unsigned int _Count=210537613) Line 145 + 0xb bytes C++
AssimpLoadFileTest.exe!std::vector<unsigned int,std::allocator<unsigned int> >::_Insert_n(std::_Vector_const_iterator<unsigned int,std::allocator<unsigned int> > _Where=..., unsigned int _Count=1, const unsigned int & _Val=0) Line 1173 + 0xf bytes C++
AssimpLoadFileTest.exe!std::vector<unsigned int,std::allocator<unsigned int> >::insert(std::_Vector_const_iterator<unsigned int,std::allocator<unsigned int> > _Where=..., const unsigned int & _Val=0) Line 878 C++
AssimpLoadFileTest.exe!std::vector<unsigned int,std::allocator<unsigned int> >::push_back(const unsigned int & _Val=0) Line 824 C++
AssimpLoadFileTest.exe!Assimp::ObjFileParser::getFace(aiPrimitiveType type=aiPrimitiveType_POLYGON) Line 319 + 0x1e bytes C++
AssimpLoadFileTest.exe!Assimp::ObjFileParser::parseFile() Line 142 C++
AssimpLoadFileTest.exe!Assimp::ObjFileParser::ObjFileParser(std::vector<char,std::allocator<char> > & Data=[216](103 'g',32 ' ',102 'f',108 'l',111 'o',111 'o',114 'r',13 '
',10 '
',118 'v',32 ' ',45 '-',53 '5',48 '0',48 '0',46 '.',48 '0',32 ' ',48 '0',46 '.',48 '0',32 ' ',45 '-',53 '5',48 '0',48 '0',46 '.',48 '0',13 '
',10 '
',118 'v',32 ' ',45 '-',53 '5',48 '0',48 '0',46 '.',48 '0',32 ' ',48 '0',46 '.',48 '0',32 ' ',53 '5',48 '0',48 '0',46 '.',48 '0',13 '
',10 '
',118 'v',32 ' ',53 '5',48 '0',48 '0',...,...), const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & strModelName="floor.obj", Assimp::IOSystem * io=0x0110f464) Line 81 C++
AssimpLoadFileTest.exe!Assimp::ObjFileImporter::InternReadFile(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & pFile="floor.obj", aiScene * pScene=0x00e7a738, Assimp::IOSystem * pIOHandler=0x0110f464) Line 145 + 0x1d bytes C++
AssimpLoadFileTest.exe!Assimp::BaseImporter::ReadFile(const Assimp::Importer * pImp=0x0110faac, const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & pFile="floor.obj", Assimp::IOSystem * pIOHandler=0x00e72e88) Line 88 + 0x2c bytes C++
AssimpLoadFileTest.exe!Assimp::Importer::ReadFile(const char * _pFile=0x0110fae8, unsigned int pFlags=32779) Line 650 + 0x18 bytes C++
AssimpLoadFileTest.exe!Assimp::Importer::ReadFile(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & pFile="floor.obj", unsigned int pFlags=32779) Line 629 C++
AssimpLoadFileTest.exe!DoTheImportThing(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & pFile="floor.obj") Line 15 + 0x11 bytes C++
AssimpLoadFileTest.exe!main() Line 34 + 0x2d bytes C++
AssimpLoadFileTest.exe!__tmainCRTStartup() Line 586 + 0x19 bytes C
AssimpLoadFileTest.exe!mainCRTStartup() Line 403 C
kernel32.dll!75a1336a()
ntdll.dll!77459f72()
ntdll.dll!77459f45()
Output:
'AssimpLoadFileTest.exe': Loaded 'C:\Visual Studio 2008\Projects\AssimpLoadFileTest\Debug\AssimpLoadFileTest.exe', Symbols loaded.
'AssimpLoadFileTest.exe': Loaded 'C:\Windows\SysWOW64\ntdll.dll'
'AssimpLoadFileTest.exe': Loaded 'C:\Windows\SysWOW64\kernel32.dll'
'AssimpLoadFileTest.exe': Loaded 'C:\Windows\SysWOW64\KernelBase.dll'
'AssimpLoadFileTest.exe': Loaded 'C:\Windows\winsxs\x86_microsoft.vc90.debugcrt_1fc8b3b9a1e18e3b_9.0.30729.6161_none_2a4f639a55563668\msvcp90d.dll', Symbols loaded.
'AssimpLoadFileTest.exe': Loaded 'C:\Windows\winsxs\x86_microsoft.vc90.debugcrt_1fc8b3b9a1e18e3b_9.0.30729.6161_none_2a4f639a55563668\msvcr90d.dll', Symbols loaded.
First-chance exception at 0x7512c41f in AssimpLoadFileTest.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0110d644..
The program '[3340] AssimpLoadFileTest.exe: Native' has exited with code 0 (0x0).
floor.obj:
g floor
v -500.0 0.0 -500.0
v -500.0 0.0 500.0
v 500.0 0.0 -500.0
v 500.0 0.0 500.0
#
vn 0 1 0
#
vt 0.0 0.0
vt 0.0 500.0
vt 500.0 0.0
vt 500.0 500.0
#
f 1/1/1 2/2/1 3/3/1
f 3/3/1 2/2/1 4/4/1
Is static local variables safe for a class that creates/uses std::threads?
Because when I use something like this:
logger& logger::get_instance(void)
{
static logger lg;
return lg;
}
And try to exit (force close) the executable, it crashes/exits improperly (somethings the Visual Studio 2012 debugger even crashes).
When I don't do that, the program exits gracefully when i force close.
Here's the stack call when it crashes
ntdll.dll!77c10dbd() Unknown
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!77b7bfdc() Unknown
kernel32.dll!75b55bab() Unknown
> msvcr110d.dll!__crtCreateThreadpoolWait(void (_TP_CALLBACK_INSTANCE *, void *, _TP_WAIT *, unsigned long) * pfnwa, void * pv, _TP_CALLBACK_ENVIRON_V1 * pcbe) Line 569 C
msvcr110d.dll!Concurrency::details::RegisterAsyncWaitAndLoadLibrary(void * waitingEvent, void (_TP_CALLBACK_INSTANCE *, void *, _TP_WAIT *, unsigned long) * callback, void * data) Line 675 C++
msvcr110d.dll!Concurrency::details::ExternalContextBase::PrepareForUse(bool explicitAttach) Line 120 C++
msvcr110d.dll!Concurrency::details::ExternalContextBase::ExternalContextBase(Concurrency::details::SchedulerBase * pScheduler, bool explicitAttach) Line 52 C++
msvcr110d.dll!Concurrency::details::SchedulerBase::GetExternalContext(bool explicitAttach) Line 1579 C++
msvcr110d.dll!Concurrency::details::SchedulerBase::AttachExternalContext(bool explicitAttach) Line 1527 C++
msvcr110d.dll!Concurrency::details::SchedulerBase::CreateContextFromDefaultScheduler() Line 569 C++
msvcr110d.dll!Concurrency::details::SchedulerBase::CurrentContext() Line 402 C++
msvcr110d.dll!Concurrency::details::LockQueueNode::LockQueueNode(unsigned int timeout) Line 616 C++
msvcr110d.dll!Concurrency::critical_section::lock() Line 1017 C++
msvcp110d.dll!mtx_do_lock(_Mtx_internal_imp_t * * mtx, const xtime * target) Line 65 C++
msvcp110d.dll!_Mtx_lock(_Mtx_internal_imp_t * * mtx) Line 144 C++
escobar.exe!std::_Mtx_lockX(_Mtx_internal_imp_t * * _Mtx) Line 68 C++
escobar.exe!std::_Mutex_base::lock() Line 43 C++
escobar.exe!std::unique_lock<std::mutex>::unique_lock<std::mutex>(std::mutex & _Mtx) Line 228 C++
escobar.exe!escobar::utilities::blocking_queue<escobar::logging::log_message *>::interrupt() Line 71 C++
escobar.exe!escobar::logging::log_worker::~log_worker() Line 17 C++
escobar.exe!escobar::logging::log_worker::`scalar deleting destructor'(unsigned int) C++
escobar.exe!escobar::logging::logger::close() Line 72 C++
escobar.exe!escobar::logging::logger::~logger() Line 27 C++
escobar.exe!`escobar::logging::logger::get_instance'::`2'::`dynamic atexit destructor for 'lg''() C++
msvcr110d.dll!doexit(int code, int quick, int retcaller) Line 585 C
msvcr110d.dll!_cexit() Line 410 C
msvcr110d.dll!__CRTDLL_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 296 C
msvcr110d.dll!_CRTDLL_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 210 C
ntdll.dll!77bb2846() Unknown
ntdll.dll!77bb2893() Unknown
ntdll.dll!77bc09c8() Unknown
ntdll.dll!77bc08ad() Unknown
KernelBase.dll!75525bbb() Unknown
KernelBase.dll!75525c51() Unknown
kernel32.dll!75b58543() Unknown
ntdll.dll!77bbac69() Unknown
ntdll.dll!77bbac3c() Unknown
Here are a couple of the functoin
log_worker::~log_worker(void)
{
this->queue.interrupt();
service.join();
}
void log_worker::run(void)
{
while (true)
{
log_message* msg;
if (this->queue.dequeue(msg) == false)
break;
this->lg->print_log_message(msg);
delete msg;
}
}
bool dequeue(T& item)
{
std::unique_lock<std::mutex> lock(m);
// handles spurious wakeups
while (!this->data_available && !this->interrupted)
cv.wait(lock);
if (this->interrupted)
return false;
item = std::move(this->front());
this->pop();
if (this->empty())
this->data_available = false;
return true;
}
void interrupt(void)
{
std::unique_lock<std::mutex> lock(m);
this->interrupted = true;
cv.notify_all();
printf("notified threads...\n");
}
Looks like you have a detached thread SchedulerBase(could be any scheduled thread which still uses logger) which is still running while your application is stopped and logger is destroyed which caused the crash.
And log_worker is dynamically allocated in the logger class.
You need to make sure all threads who use logger instance are shutdown properly before logger is destroyed
delete log_worker in logger destructor
I simply had to stop deleting things on shutdown. When you close the console using the 'X' button, it's not a proper shutdown, so It's pointless trying to shutdown threads.
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 (this project is being modernized so it was broken for a long time) it used to work fine in the same setup:
Library A is a DLL that hosts the PreProcess source function, executable B uses the DLL A and can call PreProcess source, and DLL A can also sometimes call the function itself.
But right now this is no longer the case: whenever DLL A calls the function itself, or DLL A calls another function, which in turn calls back into DLL A PreProcess source, it deadlocks.
Here's an example that works just fine from my unit testing:
BOOST_AUTO_TEST_CASE(Preprocessor)
{
std::stringstream sstream;
sstream << "void main(inout float4 vtxInput : POSITION) { }" << std::endl << std::endl;
std::string source = sstream.str();
std::string defines = "";
try
{
std::string shaderCode = Nitro::PreProcessSource(source, defines);
} catch (boost::wave::preprocess_exception& pe)
{
std::cerr << pe.what() << std::endl;
}
}
And here is the weird bit, if DO_DEADLOCK is defined to 1 in the following piece of code, the deadlock will happen:
class Tutorial00 : public Game
{
public:
// ...
Tutorial00()
: 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");
}
// ...
};
#if 1
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
#else
int main(int argc, char* argv[])
#endif
{
Tutorial00 app;
app.Run();
return 0;
}
Note that the constructor is called directly from the executable, whereas LoadContent is called from the DLL:
// In the 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 options except for BOOST_ALL_DYN_LINK, BOOST_THREAD_BUILD_DLL and the string pooling option.
The Boost unit test library is build separately as a static library.
Here is the stack trace of the working version:
Nitro.dll!boost::call_once<void (__cdecl*)(void)>(boost::once_flag & flag, void (void)* f) Line 200 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++
NitroCoreUnitTests.exe!Preprocessor::test_method() Line 16 C++
NitroCoreUnitTests.exe!Preprocessor_invoker() Line 7 + 0x1f bytes C++
...
NitroCoreUnitTests.exe!boost::unit_test::unit_test_main(boost::unit_test::test_suite * (int, char * *)* init_func, int argc, char * * argv) Line 187 C++
NitroCoreUnitTests.exe!main(int argc, char * * argv) Line 238 C++
NitroCoreUnitTests.exe!__tmainCRTStartup() Line 555 + 0x19 bytes C
NitroCoreUnitTests.exe!mainCRTStartup() Line 371 C
kernel32.dll!00000000766a652d()
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]
ntdll.dll!0000000076d9c521()
And here is the 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 South.
Thanks in advance for any help :)
I found the following ticket opened on boost's trac: boost::call_once not re-entrant (at least in win32)
It says that call_once is not re-entrant, and shouldn't be called recursively. Thus the code that I am employing is undefined behavior; the ticket was marked as "will not fix".
The solution I've taken was to create a separate DLL that only contains the PreProcessSource function.