[gcc r17-4837] libstdc++: Fix stack corruption in std::bitset stream extraction [PR124370]

Jonathan Wakely redi@gcc.gnu.org
Fri Oct 2 13:52:07 GMT 2026


https://gcc.gnu.org/g:5d419c69ce2e6b86d7da75f18736904885674219

commit r17-4837-g5d419c69ce2e6b86d7da75f18736904885674219
Author: Jonathan Wakely <jwakely@redhat.com>
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 <tkaminsk@redhat.com>

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 d581606e7dde..469c8da9ece4 100644
--- a/libstdc++-v3/include/std/bitset
+++ b/libstdc++-v3/include/std/bitset
@@ -1705,30 +1705,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>();
+}


More information about the Libstdc++-cvs mailing list