mirror of
https://github.com/boostorg/context.git
synced 2026-07-21 13:13:45 +00:00
Use mmap(2) MAP_STACK to allocate stacks on OpenBSD
Since OpenBSD 6.4 (https://www.openbsd.org/64.html), the stack pointer must point to MAP_STACK memory, or the kernel may kill the process with a signal. All stack allocators must pass MAP_STACK to mmap(2). Define BOOST_CONTEXT_USE_MAP_STACK on OpenBSD, and don't define it on other systems. This doesn't check for old versions of OpenBSD without MAP_STACK; but OpenBSD has stopped maintaining versions before 6.4. If BOOST_CONTEXT_USE_MAP_STACK is defined, then cause the stack allocators to pass MAP_STACK to mmap(2): - fixedsize_stack uses mmap/munmap instead of malloc/free. This comes from a patch in OpenBSD Ports. - protected_fixedsize_stack adds MAP_STACK to the mmap flags (as it does in OpenBSD Ports). Assume that systems with MAP_STACK also have MAP_ANON; this is true on OpenBSD. Delete POSIX comment, because I can't find MAP_ANON nor MAP_ANONYMOUS in POSIX, so these mmap calls don't conform to POSIX. - pooled_fixedsize_stack can't call munmap, because the pool's free doesn't know the allocation's size. Instead use posix_memalign to allocate memory, then mmap to replace the pages with MAP_STACK pages, so the pool's free may call std::free. OpenBSD has no <ucontext.h>, so edit test/Jamfile.v2 to skip ucontext tests on OpenBSD. This commit and https://github.com/boostorg/test/pull/231 causes libs/context/test `b2 full` to pass on OpenBSD 6.5 for 64-bit x86. `b2 fc` fails because the allocator in test_fcontext.cpp does not use MAP_STACK. The tests seem not to cover pooled_fixedsize_stack nor protected_fixedsize_stack, but they still pass when I temporarily hack callcc to use those allocators instead of fixedsize_stack.
This commit is contained in:
@@ -124,4 +124,9 @@ static constexpr std::size_t prefetch_stride{ 4 * cacheline_length };
|
||||
# include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
// stacks need mmap(2) with MAP_STACK
|
||||
# define BOOST_CONTEXT_USE_MAP_STACK
|
||||
#endif
|
||||
|
||||
#endif // BOOST_CONTEXT_DETAIL_CONFIG_H
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
#include <boost/context/stack_context.hpp>
|
||||
#include <boost/context/stack_traits.hpp>
|
||||
|
||||
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
|
||||
extern "C" {
|
||||
#include <sys/mman.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_USE_VALGRIND)
|
||||
#include <valgrind/valgrind.h>
|
||||
#endif
|
||||
@@ -42,10 +48,17 @@ public:
|
||||
}
|
||||
|
||||
stack_context allocate() {
|
||||
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
|
||||
void * vp = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
|
||||
if ( vp == MAP_FAILED) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
#else
|
||||
void * vp = std::malloc( size_);
|
||||
if ( ! vp) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
#endif
|
||||
stack_context sctx;
|
||||
sctx.size = size_;
|
||||
sctx.sp = static_cast< char * >( vp) + sctx.size;
|
||||
@@ -62,7 +75,11 @@ public:
|
||||
VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id);
|
||||
#endif
|
||||
void * vp = static_cast< char * >( sctx.sp) - sctx.size;
|
||||
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
|
||||
::munmap( vp, sctx.size);
|
||||
#else
|
||||
std::free( vp);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -21,6 +21,13 @@
|
||||
#include <boost/context/stack_context.hpp>
|
||||
#include <boost/context/stack_traits.hpp>
|
||||
|
||||
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
|
||||
extern "C" {
|
||||
#include <sys/mman.h>
|
||||
#include <stdlib.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_USE_VALGRIND)
|
||||
#include <valgrind/valgrind.h>
|
||||
#endif
|
||||
@@ -32,6 +39,31 @@
|
||||
namespace boost {
|
||||
namespace context {
|
||||
|
||||
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
|
||||
namespace detail {
|
||||
template< typename traitsT >
|
||||
struct map_stack_allocator {
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
static char * malloc( const size_type bytes) {
|
||||
void * block;
|
||||
if ( ::posix_memalign( &block, traitsT::page_size(), bytes) != 0) {
|
||||
return 0;
|
||||
}
|
||||
if ( mmap( block, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_STACK, -1, 0) == MAP_FAILED) {
|
||||
std::free( block);
|
||||
return 0;
|
||||
}
|
||||
return reinterpret_cast< char * >( block);
|
||||
}
|
||||
static void free( char * const block) {
|
||||
std::free( block);
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
template< typename traitsT >
|
||||
class basic_pooled_fixedsize_stack {
|
||||
private:
|
||||
@@ -39,7 +71,11 @@ private:
|
||||
private:
|
||||
std::atomic< std::size_t > use_count_;
|
||||
std::size_t stack_size_;
|
||||
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
|
||||
boost::pool< detail::map_stack_allocator< traitsT > > storage_;
|
||||
#else
|
||||
boost::pool< boost::default_user_allocator_malloc_free > storage_;
|
||||
#endif
|
||||
|
||||
public:
|
||||
storage( std::size_t stack_size, std::size_t next_size, std::size_t max_size) :
|
||||
|
||||
@@ -57,8 +57,9 @@ public:
|
||||
// add one page at bottom that will be used as guard-page
|
||||
const std::size_t size__ = ( pages + 1) * traits_type::page_size();
|
||||
|
||||
// conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L)
|
||||
#if defined(MAP_ANON)
|
||||
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
|
||||
void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
|
||||
#elif defined(MAP_ANON)
|
||||
void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#else
|
||||
void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
+3
-1
@@ -31,7 +31,9 @@ project boost/context/test
|
||||
rule native-impl ( properties * )
|
||||
{
|
||||
local result ;
|
||||
if ( <target-os>darwin in $(properties) || <target-os>android in $(properties) )
|
||||
if ( <target-os>android in $(properties) ||
|
||||
<target-os>darwin in $(properties) ||
|
||||
<target-os>openbsd in $(properties) )
|
||||
{
|
||||
result = <build>no ;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user