diff --git a/include/boost/json/impl/value_stack.ipp b/include/boost/json/impl/value_stack.ipp index af1b107b2..c7d9ddff1 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,15 @@ 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 + if(std::align( + alignof(value), + min_size_ * sizeof(value), + temp, size)) { + temp_ = temp; begin_ = reinterpret_cast< value*>(temp); top_ = begin_; @@ -53,6 +58,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..2858ac5bf 100644 --- a/test/value_stack.cpp +++ b/test/value_stack.cpp @@ -117,10 +117,33 @@ 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. Walk every + // misalignment; before the fix the odd offsets construct a `value` + // at a misaligned address (UBSan: misaligned constructor call). + alignas(value) unsigned char buf[4096 + alignof(value)]; + for(std::size_t off = 0; off < alignof(value); ++off) + { + value_stack st( + storage_ptr(), buf + off, sizeof(buf) - off); + st.reset(); + st.push_int64(1); + st.push_int64(2); + st.push_int64(3); + st.push_array(3); + value const jv = st.release(); + BOOST_TEST(serialize(jv) == "[1,2,3]"); + } + } + void run() { testValueStack(); + testAlignment(); } };