| Summary: | Boost.Context appears to cause Valgrind to crash | ||
|---|---|---|---|
| Product: | [Developer tools] valgrind | Reporter: | Jeremiah Willcock <jewillco> |
| Component: | general | Assignee: | Julian Seward <jseward> |
| Status: | REPORTED --- | ||
| Severity: | normal | CC: | morten.bendiksen, simonvalgrind, simonvalgrind |
| Priority: | NOR | ||
| Version First Reported In: | 3.8.0 | ||
| Target Milestone: | --- | ||
| Platform: | Compiled Sources | ||
| OS: | Linux | ||
| Latest Commit: | Version Fixed/Implemented In: | ||
| Sentry Crash Report: | |||
|
Description
Jeremiah Willcock
2012-09-02 18:41:54 UTC
Note that Boost.Context creates its own guard pages below the stacks that it allocates. Also, I tried adding a call to VALGRIND_STACK_REGISTER on the Boost.Context-allocated stacks in a (different) test program, and that does not appear to work around the problem. We're seeing the same thing at my company. We're using Boost.Context as part of a high performance server, so this means we can't use Valgrind on our product. Any help or insight anyone can give would be extremely helpful! Yes, is probably a legit bug that we should fix. Persuading Boost to not do stack switching would be a short term workaround. The goal of Boost.Context is to do the stack switching (to get user-level threads and similar constructs), so there is probably no way to avoid it. The stack handling (allocating and deallocating stacks, plus creating guard pages) has been moved into Boost.Coroutine, while context switching between stacks is still in Boost.Context. For anyone else who comes across this issue: There is code to help valgrind understand co-routines. We've had some luck with VALGRIND_STACK_REGISTER() and VALGRIND_STACK_DEREGISTER(). See: https://lists.gnu.org/archive/html/qemu-devel/2012-07/msg01579.html https://github.com/acunu/libstutter/blob/master/stutter/coroutine.cpp By making a stack allocator wrapper for boost couroutine, it worked for me.
boost::coroutines::coroutine<void>::pull_type(
[pro, this] (boost::coroutines::coroutine<void>::push_type& new_push_ptr) {}, boost::coroutines::attributes(), valgrind_stack_allocator());
#ifdef HAVE_VALGRIND_H
#include <unordered_map>
#include <valgrind/valgrind.h>
#endif
// Wraps boost::coroutine::stack_allocator, and if Valgrind is installed
// will register stacks, so that Valgrind is not confused.
class valgrind_stack_allocator {
boost::coroutines::stack_allocator allocator;
#ifdef HAVE_VALGRIND_H
std::unordered_map<void*, unsigned> stack_ids;
#endif
public:
static bool is_stack_unbound() {
return boost::coroutines::stack_allocator::is_stack_unbound();
}
static std::size_t maximum_stacksize() {
return boost::coroutines::stack_allocator::maximum_stacksize();
}
static std::size_t default_stacksize() {
return boost::coroutines::stack_allocator::default_stacksize();
}
static std::size_t minimum_stacksize() {
return boost::coroutines::stack_allocator::minimum_stacksize();
}
void allocate( boost::coroutines::stack_context & sc, std::size_t size) {
allocator.allocate(sc, size);
#ifdef HAVE_VALGRIND_H
auto res = stack_ids.insert(
std::make_pair(
sc.sp,
VALGRIND_STACK_REGISTER(sc.sp, (((char*)sc.sp) - sc.size))));
(void)res;
assert(res.second);
#endif
}
void deallocate( boost::coroutines::stack_context & sc) {
#ifdef HAVE_VALGRIND_H
auto id = stack_ids.find(sc.sp);
assert(id != stack_ids.end());
VALGRIND_STACK_DEREGISTER(id->second);
stack_ids.erase(id);
#endif
allocator.deallocate(sc);
}
};
|