diff --git a/include/boost/json/impl/value_stack.ipp b/include/boost/json/impl/value_stack.ipp index af1b107b2..5d768c626 100644 --- a/include/boost/json/impl/value_stack.ipp +++ b/include/boost/json/impl/value_stack.ipp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -40,11 +41,16 @@ stack( void* temp, std::size_t size) noexcept : sp_(std::move(sp)) - , temp_(temp) { - if(size >= min_size_ * - sizeof(value)) + // the buffer stores `value`s, so it has to be aligned for one; + // align it up the same way static_resource does for its buffer + void* const aligned = std::align( + alignof(value), + min_size_ * sizeof(value), + temp, size); + if(aligned) { + temp_ = temp; begin_ = reinterpret_cast< value*>(temp); top_ = begin_; @@ -53,6 +59,7 @@ stack( } else { + temp_ = temp; begin_ = nullptr; top_ = nullptr; end_ = nullptr; diff --git a/test/value_stack.cpp b/test/value_stack.cpp index 73df247b1..fd513e549 100644 --- a/test/value_stack.cpp +++ b/test/value_stack.cpp @@ -117,10 +117,28 @@ class value_stack_test } + void + testAlignment() + { + // a caller-supplied buffer is used to store `value`s, so the stack + // must cope with a buffer that is not aligned for one. Offsetting an + // aligned buffer by 1 makes it misaligned; before the fix that + // constructs a `value` at a misaligned address (UBSan: misaligned + // constructor call). + alignas(value) unsigned char buf[1024]; + value_stack st( + storage_ptr(), buf + 1, sizeof(buf) - 1); + st.reset(); + st.push_int64(1); + value const jv = st.release(); + BOOST_TEST(serialize(jv) == "1"); + } + void run() { testValueStack(); + testAlignment(); } };