https://gcc.gnu.org/g:3723bab816971351f3ba34b89c803f89d01bcbc4
commit r16-9790-g3723bab816971351f3ba34b89c803f89d01bcbc4 Author: Jonathan Wakely <[email protected]> Date: Thu Oct 1 22:50:13 2026 +0100 libstdc++: Fix stack corruption in std::bitset stream extraction [PR124370] The __builtin_alloca argument didn't account for the size or alignment of wide characters. Replace __builtin_alloca with an array _CharT[small ? N : 1] which is used for small, or a heap allocation otherwise. libstdc++-v3/ChangeLog: PR libstdc++/124370 * include/std/bitset (operator>>): Use array inside _Buffer instead of __builtin_alloca. * testsuite/20_util/bitset/io/input.cc: Suppress pedwarn about C++14 binary literal. * testsuite/20_util/bitset/io/wchar_t.cc: New test. Reviewed-by: Tomasz KamiĆski <[email protected]> (cherry picked from commit 5d419c69ce2e6b86d7da75f18736904885674219) Diff: --- libstdc++-v3/include/std/bitset | 31 ++++++++--------- libstdc++-v3/testsuite/20_util/bitset/io/input.cc | 2 ++ .../testsuite/20_util/bitset/io/wchar_t.cc | 39 ++++++++++++++++++++++ 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/libstdc++-v3/include/std/bitset b/libstdc++-v3/include/std/bitset index 64dae5be8bf9..9f4e5eaf1bf5 100644 --- a/libstdc++-v3/include/std/bitset +++ b/libstdc++-v3/include/std/bitset @@ -1661,30 +1661,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef std::basic_istream<_CharT, _Traits> __istream_type; typedef typename __istream_type::ios_base __ios_base; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + static const bool __use_local = _Nb * sizeof(_CharT) <= 256; + struct _Buffer { - static _GLIBCXX_CONSTEXPR bool _S_use_alloca() { return _Nb <= 256; } - - explicit _Buffer(_CharT* __p) : _M_ptr(__p) { } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + _Buffer() : _M_ptr(_M_local) + { + if _GLIBCXX_CONSTEXPR (!__use_local) + _M_ptr = new _CharT[_Nb]; + } ~_Buffer() { - if _GLIBCXX_CONSTEXPR (!_S_use_alloca()) + if _GLIBCXX_CONSTEXPR (!__use_local) delete[] _M_ptr; } - - _CharT* const _M_ptr; - }; - _CharT* __ptr; - if _GLIBCXX_CONSTEXPR (_Buffer::_S_use_alloca()) - __ptr = (_CharT*)__builtin_alloca(_Nb); - else - __ptr = new _CharT[_Nb]; - const _Buffer __buf(__ptr); #pragma GCC diagnostic pop + _CharT* _M_ptr; + _CharT _M_local[__use_local && _Nb != 0 ? _Nb : 1]; + } __buf; + + _CharT* __ptr = __buf._M_ptr; + // _GLIBCXX_RESOLVE_LIB_DEFECTS // 303. Bitset input operator underspecified const char_type __zero = __is.widen('0'); diff --git a/libstdc++-v3/testsuite/20_util/bitset/io/input.cc b/libstdc++-v3/testsuite/20_util/bitset/io/input.cc index b0e301a42b10..a01e48cf2847 100644 --- a/libstdc++-v3/testsuite/20_util/bitset/io/input.cc +++ b/libstdc++-v3/testsuite/20_util/bitset/io/input.cc @@ -42,6 +42,8 @@ void test01() VERIFY( ss.rdstate() == ios_base::goodbit ); // LWG 3199 } +#pragma GCC diagnostic ignored "-Wc++14-extensions" // 0b literals + void test02() { diff --git a/libstdc++-v3/testsuite/20_util/bitset/io/wchar_t.cc b/libstdc++-v3/testsuite/20_util/bitset/io/wchar_t.cc new file mode 100644 index 000000000000..6c7c496daa17 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/bitset/io/wchar_t.cc @@ -0,0 +1,39 @@ +// { dg-do run } + +// C++98 23.3.5.3 bitset operators + +#include <bitset> +#include <sstream> +#include <testsuite_hooks.h> + +#pragma GCC diagnostic ignored "-Wc++14-extensions" // 0b literals + +// Bug 124370 - Out-of-bounds write for wistream >> bitset +void +test_pr124370() +{ + std::wistringstream input(L"10011011001101"); + std::bitset<10> b; + input >> b; + VERIFY( b == std::bitset<10>(0b1001101100) ); +} + +// Round-trip through a wide stream. +template<int N> +void +test_round_trip() +{ + std::bitset<N> a(0b100110110011010101101010), b; + std::wstringstream ss; + ss << a; + ss >> b; + VERIFY( b == a ); +} + +int main() +{ + test_pr124370(); + test_round_trip<0>(); + test_round_trip<24>(); + test_round_trip<1024>(); +}
