New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stack overflow on GlContext creation. #989

Closed
StevenChristy opened this Issue Oct 18, 2015 · 13 comments

Comments

Projects
None yet
5 participants
@StevenChristy

StevenChristy commented Oct 18, 2015

Using the latest master version of SFML the following code like the following causes a stack overflow on context creation:

std::thread background_thread([&]() {
    sf::Context context; 
    //... load resources
    loadingCompleted = true;
});

Switching back to the 2.3.2 tag fixed the issue.

@binary1248

This comment has been minimized.

Show comment
Hide comment
@binary1248

binary1248 Oct 18, 2015

Member

This is a limitation of the current implementation, and not really caused by a stack overflow even if that is what some tools say.

If you search the SFML forums, you will find many threads where people have attempted to create contexts or perform some other OpenGL operations in secondary threads. It will not work with the current implementation if you continuously keep spawning new threads to do this.

Even if this code did work in 2.3.2, it was due to luck, because this usage is not explicitly supported, meaning that its behaviour can change when changing platforms or changing revisions, which it did in the recent commits.

There is work being done to fix this limitation, but it is not yet complete.

It would be more convenient if you could report these kinds of issues on the forum first in the future. That way we can point you to the many discussions that have already taken place in the past.

Member

binary1248 commented Oct 18, 2015

This is a limitation of the current implementation, and not really caused by a stack overflow even if that is what some tools say.

If you search the SFML forums, you will find many threads where people have attempted to create contexts or perform some other OpenGL operations in secondary threads. It will not work with the current implementation if you continuously keep spawning new threads to do this.

Even if this code did work in 2.3.2, it was due to luck, because this usage is not explicitly supported, meaning that its behaviour can change when changing platforms or changing revisions, which it did in the recent commits.

There is work being done to fix this limitation, but it is not yet complete.

It would be more convenient if you could report these kinds of issues on the forum first in the future. That way we can point you to the many discussions that have already taken place in the past.

@binary1248 binary1248 closed this Oct 18, 2015

@binary1248 binary1248 added the bug label Oct 18, 2015

@StevenChristy

This comment has been minimized.

Show comment
Hide comment
@StevenChristy

StevenChristy Oct 21, 2015

The only reason I reported it as a defect is because it worked in 2.3.2 and because the documentation for 2.3.2 says specifically this is how it is to be done:

http://www.sfml-dev.org/documentation/2.3.2/classsf_1_1Context.php

I can accept the latest is not currently supporting this, which is why I reported it so that maybe it will get fixed.

StevenChristy commented Oct 21, 2015

The only reason I reported it as a defect is because it worked in 2.3.2 and because the documentation for 2.3.2 says specifically this is how it is to be done:

http://www.sfml-dev.org/documentation/2.3.2/classsf_1_1Context.php

I can accept the latest is not currently supporting this, which is why I reported it so that maybe it will get fixed.

@binary1248

This comment has been minimized.

Show comment
Hide comment
@binary1248

binary1248 Oct 21, 2015

Member

I agree that the documentation might make it seem like legitimate use of the sf::Context class, but maybe it is because it doesn't differentiate between long-lasting threads and worker threads that are continuously spawned.

If you create a handful of threads and use those threads throughout your application from startup to exit, this problem should not occur. This was the scenario that was supposed to be provided as an example in the documentation.

If nothing was currently being done to alleviate the issue and make usage in worker threads work, then the documentation would probably end up being amended with the necessary warnings. However, as I said, we have been working on fixing the issue even before you reported it, so until that gets merged, we're going to to have to make due with the current state of things. Thanks for the report anyway.

Member

binary1248 commented Oct 21, 2015

I agree that the documentation might make it seem like legitimate use of the sf::Context class, but maybe it is because it doesn't differentiate between long-lasting threads and worker threads that are continuously spawned.

If you create a handful of threads and use those threads throughout your application from startup to exit, this problem should not occur. This was the scenario that was supposed to be provided as an example in the documentation.

If nothing was currently being done to alleviate the issue and make usage in worker threads work, then the documentation would probably end up being amended with the necessary warnings. However, as I said, we have been working on fixing the issue even before you reported it, so until that gets merged, we're going to to have to make due with the current state of things. Thanks for the report anyway.

@StevenChristy

This comment has been minimized.

Show comment
Hide comment
@StevenChristy

StevenChristy Oct 25, 2015

You wrote:
"If you create a handful of threads and use those threads throughout your application from startup to exit, this problem should not occur."
and
"This is a limitation of the current implementation, and not really caused by a stack overflow even if that is what some tools say."

I think I must have failed to communicate the issue concisely. I'll correct this first by asserting that what I am reporting is a straight up defect in in the latest version SFML, and it has nothing to do with OpenGL or the lifetime of threads or any of that other stuff. Now that in itself is not helpful to you, but I wanted to make it clear what I am reporting is not design related. I took some time to track down the issue so I could describe it in more detail, here is the call stack of the stack overflow:

#0 (anonymous namespace)::getInternalContext() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlContext.cpp:155
#1 sf::priv::GlContext::ensureContext() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlContext.cpp:213
#2 sf::GlResource::GlResource() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlResource.cpp:60
#3 sf::Context::Context() at /home/steven/Projects/libs/SFML/src/SFML/Window/Context.cpp:60
#4 (anonymous namespace)::getInternalContext() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlContext.cpp:155
#5 sf::priv::GlContext::ensureContext() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlContext.cpp:213
#6 sf::GlResource::GlResource() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlResource.cpp:60
#7 sf::Context::Context() at /home/steven/Projects/libs/SFML/src/SFML/Window/Context.cpp:60
#8 AppState::<lambda()>::operator()(void) const() at /home/steven/Projects/my-game/src/App.cpp:96
#9 std::_Bind_simple<AppState::doLoading()::<lambda()>()>::_M_invoke<>(std::_Index_tuple<>)() at /usr/include/c++/5/functional:1531
#10 std::_Bind_simple<AppState::doLoading()::<lambda()>()>::operator()(void)() at /usr/include/c++/5/functional:1520
#11 std::thread::_Impl<std::_Bind_simple<AppState::doLoading()::<lambda()>()> >::_M_run(void)() at /usr/include/c++/5/thread:115
#12 ??() at /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#13 start_thread() at /build/buildd/glibc-2.21/nptl/pthread_create.c:333
#14 clone() at /build/buildd/glibc-2.21/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:109

The problem is that creating an instance sf::Context in any thread will lead to endless recursion. This is because creating a sf::Context eventually calls GlContext::ensureContext() which calls getInternalContext() which creates a new sf::Context and the process repeats indefinitely.

A quick and dirty fix would be to use a thread local var as a recursion guard in ensureContext() to prevent it from leading to recursion. I tested this and corrected the problem immediately:

__thread int contextCount = 0;
void GlContext::ensureContext()
{
    if ( contextCount == 0 )
        contextCount++;
    else
        return;
    // If there's no active context on the current thread, activate an internal one
    if (!currentContext)
        getInternalContext()->setActive(true);
    contextCount--;
}

That is definately not a great long term solution. Having more knowledge of SFML you might be able to identify a more elegant way.

StevenChristy commented Oct 25, 2015

You wrote:
"If you create a handful of threads and use those threads throughout your application from startup to exit, this problem should not occur."
and
"This is a limitation of the current implementation, and not really caused by a stack overflow even if that is what some tools say."

I think I must have failed to communicate the issue concisely. I'll correct this first by asserting that what I am reporting is a straight up defect in in the latest version SFML, and it has nothing to do with OpenGL or the lifetime of threads or any of that other stuff. Now that in itself is not helpful to you, but I wanted to make it clear what I am reporting is not design related. I took some time to track down the issue so I could describe it in more detail, here is the call stack of the stack overflow:

#0 (anonymous namespace)::getInternalContext() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlContext.cpp:155
#1 sf::priv::GlContext::ensureContext() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlContext.cpp:213
#2 sf::GlResource::GlResource() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlResource.cpp:60
#3 sf::Context::Context() at /home/steven/Projects/libs/SFML/src/SFML/Window/Context.cpp:60
#4 (anonymous namespace)::getInternalContext() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlContext.cpp:155
#5 sf::priv::GlContext::ensureContext() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlContext.cpp:213
#6 sf::GlResource::GlResource() at /home/steven/Projects/libs/SFML/src/SFML/Window/GlResource.cpp:60
#7 sf::Context::Context() at /home/steven/Projects/libs/SFML/src/SFML/Window/Context.cpp:60
#8 AppState::<lambda()>::operator()(void) const() at /home/steven/Projects/my-game/src/App.cpp:96
#9 std::_Bind_simple<AppState::doLoading()::<lambda()>()>::_M_invoke<>(std::_Index_tuple<>)() at /usr/include/c++/5/functional:1531
#10 std::_Bind_simple<AppState::doLoading()::<lambda()>()>::operator()(void)() at /usr/include/c++/5/functional:1520
#11 std::thread::_Impl<std::_Bind_simple<AppState::doLoading()::<lambda()>()> >::_M_run(void)() at /usr/include/c++/5/thread:115
#12 ??() at /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#13 start_thread() at /build/buildd/glibc-2.21/nptl/pthread_create.c:333
#14 clone() at /build/buildd/glibc-2.21/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:109

The problem is that creating an instance sf::Context in any thread will lead to endless recursion. This is because creating a sf::Context eventually calls GlContext::ensureContext() which calls getInternalContext() which creates a new sf::Context and the process repeats indefinitely.

A quick and dirty fix would be to use a thread local var as a recursion guard in ensureContext() to prevent it from leading to recursion. I tested this and corrected the problem immediately:

__thread int contextCount = 0;
void GlContext::ensureContext()
{
    if ( contextCount == 0 )
        contextCount++;
    else
        return;
    // If there's no active context on the current thread, activate an internal one
    if (!currentContext)
        getInternalContext()->setActive(true);
    contextCount--;
}

That is definately not a great long term solution. Having more knowledge of SFML you might be able to identify a more elegant way.

@binary1248

This comment has been minimized.

Show comment
Hide comment
@binary1248

binary1248 Oct 28, 2015

Member

Hmm... yes... the problem is more clear now. This regression was introduced in 2752bbc.

Since, like I said above, a more general solution that removes internal contexts entirely is in the works, you can try to fix this yourself by reverting the changes introduced to GlContext.cpp as shown here.

The problem with the workaround you are currently using is that it prevents GL resources (e.g. sf::Shader and sf::Texture) from making sure a context is active when they do their work if they are the first thing that is created, i.e. before any windows. It might fix the problem in your specific scenario, but it can't be seen as a general solution to the problem.

But... like I said, an even better solution is being worked on which will hopefully be done some time in the near future.

Member

binary1248 commented Oct 28, 2015

Hmm... yes... the problem is more clear now. This regression was introduced in 2752bbc.

Since, like I said above, a more general solution that removes internal contexts entirely is in the works, you can try to fix this yourself by reverting the changes introduced to GlContext.cpp as shown here.

The problem with the workaround you are currently using is that it prevents GL resources (e.g. sf::Shader and sf::Texture) from making sure a context is active when they do their work if they are the first thing that is created, i.e. before any windows. It might fix the problem in your specific scenario, but it can't be seen as a general solution to the problem.

But... like I said, an even better solution is being worked on which will hopefully be done some time in the near future.

@binary1248

This comment has been minimized.

Show comment
Hide comment
@binary1248

binary1248 Jan 15, 2016

Member

Fixed by #1002.

Member

binary1248 commented Jan 15, 2016

Fixed by #1002.

@miki151

This comment has been minimized.

Show comment
Hide comment
@miki151

miki151 Apr 19, 2016

Just giving you a heads up that this problem occured from me yesterday with a fresh VS14 build from master. The stacktrace ended as follows:

ntdll.dll!__SEH_prolog4�() Unknown
ntdll.dll!_RtlAllocateHeap@12�() Unknown
ucrtbase.dll!malloc() Unknown
sfml-window-2.dll!operator new(unsigned int size) Line 19 C++
sfml-window-2.dll!anonymous namespace'::getInternalContext() Line 159 C++ sfml-window-2.dll!sf::priv::GlContext::ensureContext() Line 217 C++ sfml-window-2.dll!sf::GlResource::GlResource() Line 61 C++ sfml-window-2.dll!sf::Context::Context() Line 61 C++ sfml-window-2.dll!anonymous namespace'::getInternalContext() Line 159 C++
sfml-window-2.dll!sf::priv::GlContext::ensureContext() Line 217 C++
sfml-window-2.dll!sf::GlResource::GlResource() Line 61 C++
sfml-window-2.dll!sf::Context::Context() Line 61 C++
sfml-window-2.dll!`anonymous namespace'::getInternalContext() Line 159 C++

miki151 commented Apr 19, 2016

Just giving you a heads up that this problem occured from me yesterday with a fresh VS14 build from master. The stacktrace ended as follows:

ntdll.dll!__SEH_prolog4�() Unknown
ntdll.dll!_RtlAllocateHeap@12�() Unknown
ucrtbase.dll!malloc() Unknown
sfml-window-2.dll!operator new(unsigned int size) Line 19 C++
sfml-window-2.dll!anonymous namespace'::getInternalContext() Line 159 C++ sfml-window-2.dll!sf::priv::GlContext::ensureContext() Line 217 C++ sfml-window-2.dll!sf::GlResource::GlResource() Line 61 C++ sfml-window-2.dll!sf::Context::Context() Line 61 C++ sfml-window-2.dll!anonymous namespace'::getInternalContext() Line 159 C++
sfml-window-2.dll!sf::priv::GlContext::ensureContext() Line 217 C++
sfml-window-2.dll!sf::GlResource::GlResource() Line 61 C++
sfml-window-2.dll!sf::Context::Context() Line 61 C++
sfml-window-2.dll!`anonymous namespace'::getInternalContext() Line 159 C++

@eXpl0it3r

This comment has been minimized.

Show comment
Hide comment
@eXpl0it3r

eXpl0it3r Apr 19, 2016

Member

Well did you try #1002, @miki151?

Member

eXpl0it3r commented Apr 19, 2016

Well did you try #1002, @miki151?

@miki151

This comment has been minimized.

Show comment
Hide comment
@miki151

miki151 Apr 19, 2016

Sorry, I thought this had been fixed in master.

miki151 commented Apr 19, 2016

Sorry, I thought this had been fixed in master.

@eXpl0it3r

This comment has been minimized.

Show comment
Hide comment
@eXpl0it3r

eXpl0it3r Apr 19, 2016

Member

If it had been fixed in master, this issue wouldn't still be open. 😉

Member

eXpl0it3r commented Apr 19, 2016

If it had been fixed in master, this issue wouldn't still be open. 😉

@eXpl0it3r

This comment has been minimized.

Show comment
Hide comment
@eXpl0it3r

eXpl0it3r Oct 6, 2016

Member

Should be fix with cca38d9 in the 2.4.x branch.

Member

eXpl0it3r commented Oct 6, 2016

Should be fix with cca38d9 in the 2.4.x branch.

@eXpl0it3r eXpl0it3r closed this Oct 6, 2016

@OrderNexus

This comment has been minimized.

Show comment
Hide comment
@OrderNexus

OrderNexus Oct 26, 2016

This issue wasn't resolved in the newest build (Oct 24th). Any time loadFromFile is called inside a thread, the program still hangs:

test.exe!sf::priv::MutexImpl::lock() Line 52
test.exe!sf::Mutex::lock() Line 57
test.exe!sf::Lock::Lock(sf::Mutex & mutex) Line 39
test.exe!sf::GlResource::TransientContextLock::TransientContextLock() Line 79
test.exe!sf::Texture::bind(const sf::Texture * texture, sf::Texture::CoordinateType coordinateType) Line 619
test.exe!sf::RenderTarget::applyTexture(const sf::Texture * texture) Line 492
test.exe!sf::RenderTarget::clear(const sf::Color & color) Line 106

OrderNexus commented Oct 26, 2016

This issue wasn't resolved in the newest build (Oct 24th). Any time loadFromFile is called inside a thread, the program still hangs:

test.exe!sf::priv::MutexImpl::lock() Line 52
test.exe!sf::Mutex::lock() Line 57
test.exe!sf::Lock::Lock(sf::Mutex & mutex) Line 39
test.exe!sf::GlResource::TransientContextLock::TransientContextLock() Line 79
test.exe!sf::Texture::bind(const sf::Texture * texture, sf::Texture::CoordinateType coordinateType) Line 619
test.exe!sf::RenderTarget::applyTexture(const sf::Texture * texture) Line 492
test.exe!sf::RenderTarget::clear(const sf::Color & color) Line 106
@eXpl0it3r

This comment has been minimized.

Show comment
Hide comment
@eXpl0it3r

eXpl0it3r Oct 26, 2016

Member

That seems like a different issue (I at least don't see a stack overflow here), so make sure to create a forum thread about it with enough information (minimal and complete code example, etc.).

Member

eXpl0it3r commented Oct 26, 2016

That seems like a different issue (I at least don't see a stack overflow here), so make sure to create a forum thread about it with enough information (minimal and complete code example, etc.).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment