[context] Crash in case of exception from a context
I use boost::context to implement cooperative multitasking. At the moment I use boost 1.57 on Windows 7 with VisualStudio 2013. Everything works fine until I throw an exception from a context created by "boost::context::make_fcontext(.......)". I have seen someone had the same problem and it was caused by the Windows OS, that checks the exception hierarchy in the stack and if it finds that the starting point is not the one that should come from the OS then it terminates the process. It suspects some malitious code that corrupted the stack. http://www.blinnov.com/en/2013/04/11/english-boostcontext-and-seh/ This guy metioned in his blogpost, that this problem was solved in boost 1.53 ("Boost 1.53 has updated and fixed version of boost::context library that addresses exactly this problem. "), but somehow I still have the same thing in 1.57. Is there some special preprocessor flag (#define) that I have to activate to get this fix? Thanks! Tamas
On Tue, Mar 10, 2015 at 10:32 AM,
I use boost::context to implement cooperative multitasking. At the moment I use boost 1.57 on Windows 7 with VisualStudio 2013.
Everything works fine until I throw an exception from a context created by "boost::context::make_fcontext(.......)".
This guy metioned in his blogpost, that this problem was solved in boost 1.53 ("Boost 1.53 has updated and fixed version of boost::context library that addresses exactly this problem. "), but somehow I still have the same thing in 1.57. Is there some special preprocessor flag (#define) that I have to activate to get this fix?
That contradicts what the Boost 1.57 documentation itself says [0]: "Exceptions in context-function If the context-function emits an exception, the behaviour is undefined. (!) Important context-function should wrap the code in a try/catch block." [0] http://www.boost.org/doc/libs/1_57_0/libs/context/doc/html/context/context.h...
I use boost::context to implement cooperative multitasking. At the moment I use boost 1.57 on Windows 7 with VisualStudio 2013.
Everything works fine until I throw an exception from a context created by "boost::context::make_fcontext(.......)".
This guy metioned in his blogpost, that this problem was solved in boost 1.53 ("Boost 1.53 has updated and fixed version of boost::context
Actually the exception never leaves the stack frame of the context,
because I have put a try catch block inside the context-function as it was
recommended. - If I got the docs right
Here is a small demo. This crashes from V2013 standard C++ unit test.
When I step on the exception throwing line (the exception type does not
matter) then I get the "First-chance exception at 0x71E026A2 (clr.dll) in
vstest.executionengine.x86.exe: 0x80000001: Not implemented (parameters:
0x00000001, 0x0644AC84)." exception and when I pass it to the system then
a lot of "0xC0000005: Access violation" exceptions.
I have also played around with the stack size, but it does not seem to
have any effect.
void fException()
{
std::cout << "I am still ok" << std::endl;
throw int(42); // The crash occurs here
}
void f1(intptr_t)
{
try
{
std::cout << "Greetings from context f1" << std::endl;
fException();
std::cout << "Never reach this" << std::endl;
}
catch (...)
{
std::cout << "Exception caught" << std::endl;
}
}
void test()
{
std::size_t size(512*1024);
char* stack1((char*)std::malloc(size));
void* stackPointer1(stack1 + size);
boost::context::fcontext_t fcm, fc1;
fc1 = boost::context::make_fcontext(stackPointer1, size, f1);
std::cout << "Greetings from main thread stack" << std::endl;
boost::context::jump_fcontext(&fcm, fc1, 0);
}
From: Nat Goodspeed
that addresses exactly this problem. "), but somehow I still have the same thing in 1.57. Is there some special preprocessor flag (#define) that I have to activate to get this fix?
That contradicts what the Boost 1.57 documentation itself says [0]: "Exceptions in context-function If the context-function emits an exception, the behaviour is undefined. (!) Important context-function should wrap the code in a try/catch block." [0] http://www.boost.org/doc/libs/1_57_0/libs/context/doc/html/context/context.h... _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
The problem here is most likely due to Visual C++ using SEH to implement C++ exceptions. SEH uses a linked list of function pointers on the stack to process exceptions. SEH requires this linked list be on the stack, and will kill the process if it encounters one that is not. SEH is also used for normally fatal program errors (divide by zero, null pointer dereference, invalid instruction, etc) no matter what compiler is used, so even MinGW or any other C++ compiler will need this change for everything to work as it should. The solution is actually pretty simple - push the current SEH list's head onto the stack before the context switch, and restore it when resuming execution, with each context initializing its own list with UnhandledExceptionFilter during either construction or first run (like a new thread would). But maybe such a fix is out of scope for the context library?l
2015-03-14 6:37 GMT+01:00 Nathaniel Fries
The solution is actually pretty simple - push the current SEH list's head onto the stack before the context switch, and restore it when resuming execution, with each context initializing its own list with UnhandledExceptionFilter during either construction or first run (like a new thread would). But maybe such a fix is out of scope for the context library?l
boost.context already installs SEH structures on the stack - the unit-tests of boost.context already check throwing/catching exceptions -> http://www.boost.org/development/tests/master/developer/context.html http://www.boost.org/development/tests/develop/developer/context.html
I have copied the essence from the unit test and put it into my Visual
Studio (VS2013 Version 12.31101.00 Update4) environment, but still
crashes. The project is a natvie C++ project (not mixed mode .NET) and in
"Configuration Properties/C/C++/Code Generation/Enable C++ Exceptions" is
set to "Yes(/EHsc)". However there is another option : "Yes with SEH
Exceptions (/EHa)", but does not seem to fix the issue.
Meanwhile I have implemented a workaround (see below): for each context I
create a thread. As soon as this new thread is started I switch it to
another context (created by boost::context::make_fcontext) and block it
there on a condition variable. Then I use the original stack of the
thread. This "hijacked" stack can cope with exceptions, just as I would
expect. When I want to release the context then I just simply release the
blocked thread and switch it back to its original context. This way I can
make sure that the stack of the thread is also correctly unwound.
#include "stdafx.h"
#include "boost/context/all.hpp"
#include
stack_allocator;
void test()
{
stack_allocator alloc;
void * stackPointer = alloc.allocate(stack_allocator
::default_stacksize());
fc1 = boost::context::make_fcontext(stackPointer, stack_allocator
::minimum_stacksize(), f1);
std::cout << "Greetings from main thread stack" << std::endl;
boost::context::jump_fcontext(&fcm, fc1, 0);
}
TEST_CLASS(BoostContextTest)
{
public:
TEST_METHOD(ExceptionContextTest)
{
test();
}
};
//
======================================================================================================================================================================================
// This class starts a thread and switches that thread to a context where
it is parking.
// Meanwhile we can use the original stack of the thread. This way the
stack of the thread temporarily hijacked
// The reason why the stack of a real thread is needed for the context is
the exception handling.
// The context that boost::context makes does not work with exceptions
class HijackedThread
{
public:
HijackedThread(std::size_t stackSize, boost::context::fcontext_t&
contextHandle)
: _threadParkingContextStack(new ContextStack(64 * 1024))
, _threadContextHandle(contextHandle)
, _threadParkingContextHandle(nullptr)
, _threadInParkingContext(false)
, _releaseParkingThread(false)
{
CreateAndParkThread(stackSize);
WaitForThreadToPark();
}
~HijackedThread()
{
ReleaseParkingThread();
}
bool IsMethodSet()
{
auto isMethodSet = (bool)_method;
return isMethodSet;
}
void SetMethod(std::function
participants (4)
-
Nat Goodspeed
-
Nathaniel Fries
-
Oliver Kowalke
-
Tamas.Ruszkai@leica-geosystems.com