Sign in to follow this  

std::string, multithreading, and c_str

This topic is 3857 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

i really couldnt find much on the topic of unhandled exception: user breakpoint after researching it, i think the c_str function is causing issues with multithreading, there is no obvious blinking lights telling me that this is the problem but after 3 or 4 hours of adding thread safe critical sections through my whole engine, i am sure that the error is contained to where c_str is passed over to the D3DX functions. worse is that its pretty hard to find information about why an exception would be thrown without any information so what i have found after a LOT of research i feel like, getting an unhandled exception that says nothing more than user breakpoint is because of stack corruption. also it recommended to use pageheap to find out where this happened, however im going to take the std::string and wrap it out to a const char * that D3DX wants i think it will remove the issues, i will post back with results

Share this post


Link to post
Share on other sites
That's not likely to solve anything, c_str() is going to return a const char* anyway.

The problem is likely much more subtle, you're obviously doing something naughty though. Trust me, it's your code, not the SC++L and not the D3DX library.

Why don't you post the code in question and provide a more detailed breakdown of the problem as you observe it?

Share this post


Link to post
Share on other sites
The pointer returned by c_str is invalid as soon as you call any non-const methods of the string. If multiple threads are accessing the string simultaneously, you need to ensure that no thread calls a mutating method while another thread is using the pointer from c_str.

Share this post


Link to post
Share on other sites
You need to provide more information to better diagnose the problem.

If you are using Visual Studio you should read http://msdn2.microsoft.com/en-us/library/c9ceah3b(VS.71).aspx about the thread safety guarantees.

If you are linking against the Multi-threaded CRT then you have some basics guarantees, but if you plan to read/write the string from multiple threads you need to provide a readers/writers lock or similar construct. You might even want to wrap std::string into a thread safe class for reading and writing. Or you can redesign your application to avoid dealing with global strings.

It is also possible that this has nothing to do with multithreaded and could be a problem with your code/logic. Writing code multi-threaded architectures and code is a non-trivial task.

Share this post


Link to post
Share on other sites
the errors are not contained to any one set of code, the are all over the place something is corrupting the heap somewhere its not the c_str(i knew if i called certain functions it was void but there was no movement) like i was thinking there are a few places it is happening frequently but every build the exception is thrown at a different place. im locking resources like i should be so somewhere i have some stray function jacking things up and its not getting caught until way later it frequently happens on my calls to present the scene, or create resources via D3DX

for clarification all my resources, including the D3D Device have critical sections that are locked in wrapper functions, but most of the time my second thread(resource loader) is sleeping while the exception is thrown anyways

Share this post


Link to post
Share on other sites
"unhandled exception that says nothing more than user breakpoint ", most code generators fill up unused code regions with the instruction int 3; (x86) which is a user breakpoint, this makes it possible to catch cases in which you jump to an invalid code address.

Your instruction pointer or your return address (which lives on the stack) are pointing to the wrong address, this could be caused by stack corruption, but could also be caused by other reasons.

Share this post


Link to post
Share on other sites
Are you using DX for rendering?
Are you loading resources on one thread and using them on another?
Do you use the multi-threaded flag when you create the device?

Share this post


Link to post
Share on other sites
awesome information, so it is stack corruption, the question is how to debug stack corruption, its not exactly like debugging a regular code issue normally u breakpoint where problem function occurs, then u just step through watching values and see where math went wrong or how you ended up with NULL pointer, this is totally different

Share this post


Link to post
Share on other sites

CDOResource::CDOResource()
{
Priority = 500;
m_bValid = false;
InitializeCriticalSection(&Crit_sect);
}

CDOResource::~CDOResource()
{
DeleteCriticalSection(&Crit_sect);
}

bool CDOResource::Load()
{
return true;
}

void CDOResource::Free()
{
}

bool CDOResource::Lock()
{
EnterCriticalSection(&Crit_sect);
if(m_bValid)
return true;
return false;
}

void CDOResource::ReleaseLock()
{
LeaveCriticalSection(&Crit_sect);
}

Share this post


Link to post
Share on other sites
what is your high level usage of CDOResource?
I assume both threads get a pointer to it, and make sure that resources are locked and unlocked before being accessed, right?
Where do strings come into play, how are they shared?

Share this post


Link to post
Share on other sites
Note also that the pattern you are using can lead to deadlocks. If the code is used like this:

if (resource->Lock())
{
// .. use resource

resource->Unlock();
}

if the resource does not exist then you never leave the critical section.

Share this post


Link to post
Share on other sites
sorry was on out for vacation

all resources are derived from the class and yes it can dead lock if resource is locked twice by same thread but most of the time the function calls lock and unlock the resource as needed. i think somewhere something is just going stray in memory

Share this post


Link to post
Share on other sites
as called this is the disassembly

7C90122B nop
7C90122C nop
7C90122D nop
7C90122E nop
7C90122F nop
7C901230 int 3

in ntdll.dll deep called by direct x called by d3dx

this time called by the 2nd line here

Lock();
HRESULT hr = D3DXCreateEffectFromFileA(m_pD3DDevice, Filename.c_str(), pDefines, pInclude, Flags, pPool, ppEffect, ppCompilationErrors);
ReleaseLock();

called as follows

if(FAILED(g_CDODevice.CreateEffectFromFile(Filename, NULL, NULL, dwShaderFlags, NULL, &m_pEffect, NULL)))

Share this post


Link to post
Share on other sites
Superficial; the location it jumps to is irrelevant. You're probably passing a bogus pointer. Check the parameters to the call to CreateEffectFromFile, make sure they're all valid (use a debugger).

It's definitely your fault, unfortunately it's not definitely at the one line of code you posted. Memory corruption bugs are often very subtle, and the actual cause of the bug can often be very far from where the bug manifests itself. If you're not willing to post more of your code, you're not going to be able to get much more help.

Share this post


Link to post
Share on other sites
My comment about the deadlock is not that a thread locking twice will cause a deadlock, the comment is that if the usage pattern of lock/unlock is what I illustrated then you can have deadlocks. Your API could be improved in that sense, but that is not relevant to the problem you have.

Going back to the issue at hand, you want to make sure that all the parameters you pass to D3DXCreateEffectFromFile (or other APIs) are stack based or if they are global that accessing them is safe from multiple threads.

If the Filename parameter is not local to the loading thread, and could be modified by other threads you can certainly run into problems.

If the usage is:

Device->LoadResource

Device::LoadResource
Enqueue request to Load Thread

LoadThread
LockResource
LoadEffect
UnloackResource

If the parameters you pass to load resource are references or pointers they can either be out of scope and be overriden when the load thread is running.

If the problem is heap corruption (unlikely) there are some things you can do on Windows to try to catch the problem, but is painful. I think there is a way to turn on a validating heap on windows, but I do not recall the details.

For overruns or underruns there used to be a useful tool called BoundsChecker, not sure if it still exists or if they have a trial version, but if they do you might be able to use it to help you diagnose your problem.

Share this post


Link to post
Share on other sites
yoshscout you are protecting the potential for the class CDOResource from being copied and passing by a type of reference aren't you?
ie copy constructor in protected/private.
assignment operator in protected/private.

If you do not do this, two classes may try and delete the same mutex when leaving scope.

Share this post


Link to post
Share on other sites
i might be misunderstanding your question but objects are generally passed via pointer which is sorta via reference

copy constructor is not protected nor is assignment operator

i think this is whats going on http://www.debuginfo.com/tips/userbpntdll.html

Share this post


Link to post
Share on other sites
this just popped in the debugger for the first time outta no where

===========================================================
VERIFIER STOP 00000003: pid 0x6A4: multithreaded access in HEAP_NO_SERIALIZE heap

02151000 : Heap handle
000008E8 : Thread owning heap lock
0000084C : Current thread trying to acquire the heap lock
00000000 :
===========================================================

after hex converting it and cross referencing to the debuggers values for my threads the main thread owns lock on heap and the resource loader is trying to acquire the heap lock

Share this post


Link to post
Share on other sites
Are you sure you are linking against the multi-threaded version of the CRT?
If your project is split across multiple dlls you need to make sure everybody is linking against the multi-threaded version of the CRT.

Arguments passed by pointer or by reference are equivalent. If you create an object on thread 1 and pass a pointer to it to thread 2 then you can run into several problems. The first problem is if the object passed was created on the stack of thread 1 since by the time thread 2 tries to use it the stack of thread 1 has been cleaned up or modified.

Share this post


Link to post
Share on other sites
yep, all /MTd or /MT - multithreaded runtime, we are gonna have a checklist by the time we find this one, there is a static library at the core of the engine i don't use dll's - something i prefer about linking against static library, game has patcher so its just as easy to update exe as dll

man this bites the big one

Share this post


Link to post
Share on other sites

This topic is 3857 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this