diff options
author | Robert Hensing <robert@roberthensing.nl> | 2020-10-30 20:55:53 +0100 |
---|---|---|
committer | Robert Hensing <robert@roberthensing.nl> | 2020-10-30 21:21:59 +0100 |
commit | c4d903ddb009aa6472530699e154d85a24eac51d (patch) | |
tree | 684cdcab5dffc917082d5f997010babebb8e2706 /src/libutil/serialise.cc | |
parent | dc5696b84f55a6706cddc3d747ef1aeffb564f43 (diff) |
Fix memory corruption caused by GC-invisible coroutine stacks
Crucially this introduces BoehmGCStackAllocator, but it also
adds a bunch of wiring to avoid making libutil depend on bdw-gc.
Part of the solutions for #4178, #4200
Diffstat (limited to 'src/libutil/serialise.cc')
-rw-r--r-- | src/libutil/serialise.cc | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc index 5c9f6f901..28f6968d0 100644 --- a/src/libutil/serialise.cc +++ b/src/libutil/serialise.cc @@ -171,6 +171,39 @@ size_t StringSource::read(unsigned char * data, size_t len) #error Coroutines are broken in this version of Boost! #endif +/* A concrete datatype allow virtual dispatch of stack allocation methods. */ +struct VirtualStackAllocator { + StackAllocator *allocator = StackAllocator::defaultAllocator; + + boost::context::stack_context allocate() { + return allocator->allocate(); + } + + void deallocate(boost::context::stack_context sctx) { + allocator->deallocate(sctx); + } +}; + + +/* This class reifies the default boost coroutine stack allocation strategy with + a virtual interface. */ +class DefaultStackAllocator : public StackAllocator { + boost::coroutines2::default_stack stack; + + boost::context::stack_context allocate() { + return stack.allocate(); + } + + void deallocate(boost::context::stack_context sctx) { + deallocate(sctx); + } +}; + +static DefaultStackAllocator defaultAllocatorSingleton; + +StackAllocator *StackAllocator::defaultAllocator = &defaultAllocatorSingleton; + + std::unique_ptr<Source> sinkToSource( std::function<void(Sink &)> fun, std::function<void()> eof) @@ -195,7 +228,7 @@ std::unique_ptr<Source> sinkToSource( size_t read(unsigned char * data, size_t len) override { if (!coro) - coro = coro_t::pull_type([&](coro_t::push_type & yield) { + coro = coro_t::pull_type(VirtualStackAllocator{}, [&](coro_t::push_type & yield) { LambdaSink sink([&](const unsigned char * data, size_t len) { if (len) yield(std::string((const char *) data, len)); }); |