public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-6960] libstdc++: Avoid overflow when appending to std::filesystem::path
@ 2024-01-05 14:42 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2024-01-05 14:42 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:d4cd871d15b813caa4b9016f34ebbda3277da4f8

commit r14-6960-gd4cd871d15b813caa4b9016f34ebbda3277da4f8
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Jan 5 13:40:06 2024 +0000

    libstdc++: Avoid overflow when appending to std::filesystem::path
    
    This prevents a std::filesystem::path from exceeding INT_MAX/4
    components (which is unlikely to ever be a problem except on 16-bit
    targets). That limit ensures that the capacity*1.5 calculation doesn't
    overflow. We should also check that we don't exceed SIZE_MAX when
    calculating how many bytes to allocate. That only needs to be checked
    when int is at least as large as size_t, because otherwise we know that
    the product INT_MAX/4 * sizeof(value_type) will fit in SIZE_MAX. For
    targets where size_t is twice as wide as int this obviously holds. For
    msp430-elf we have 16-bit int and 20-bit size_t, so the condition holds
    as long as sizeof(value_type) fits in 7 bits, which it does.
    
    We can also remove some floating-point arithmetic in operator/= which
    ensures exponential growth of the buffer. That's redundant because
    path::_List::reserve does that anyway (and does so more efficiently
    since the commit immediately before this one).
    
    libstdc++-v3/ChangeLog:
    
            * src/c++17/fs_path.cc (path::_List::reserve): Limit maximum
            size and check for overflows in arithmetic.
            (path::operator/=(const path&)): Remove redundant exponential
            growth calculation.

Diff:
---
 libstdc++-v3/src/c++17/fs_path.cc | 35 ++++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/libstdc++-v3/src/c++17/fs_path.cc b/libstdc++-v3/src/c++17/fs_path.cc
index a2d3c54a88a..d33b8d96663 100644
--- a/libstdc++-v3/src/c++17/fs_path.cc
+++ b/libstdc++-v3/src/c++17/fs_path.cc
@@ -35,6 +35,7 @@
 #include <algorithm>
 #include <array>
 #include <bits/stl_uninitialized.h>
+#include <ext/numeric_traits.h> // __gnu_cxx::__int_traits
 
 namespace fs = std::filesystem;
 using fs::path;
@@ -447,11 +448,30 @@ path::_List::reserve(int newcap, bool exact = false)
 
   if (curcap < newcap)
     {
-      const int nextcap = curcap + curcap / 2;
-      if (!exact && newcap < nextcap)
-	newcap = nextcap;
+      if (!exact)
+	{
+	  const int nextcap = curcap + curcap / 2;
+	  if (newcap < nextcap)
+	    newcap = nextcap;
+	}
+
+      using __gnu_cxx::__int_traits;
+      // Nobody should need paths with this many components.
+      if (newcap >= __int_traits<int>::__max / 4)
+	std::__throw_bad_alloc();
 
-      void* p = ::operator new(sizeof(_Impl) + newcap * sizeof(value_type));
+      size_t bytes;
+      if constexpr (__int_traits<int>::__max >= __int_traits<size_t>::__max)
+	{
+	  size_t components;
+	  if (__builtin_mul_overflow(newcap, sizeof(value_type), &components)
+		|| __builtin_add_overflow(sizeof(_Impl), components, &bytes))
+	    std::__throw_bad_alloc();
+	}
+      else // This won't overflow, even for 20-bit size_t on msp430.
+	bytes = sizeof(_Impl) + newcap * sizeof(value_type);
+
+      void* p = ::operator new(bytes);
       std::unique_ptr<_Impl, _Impl_deleter> newptr(::new(p) _Impl{newcap});
       const int cursize = curptr ? curptr->size() : 0;
       if (cursize)
@@ -588,13 +608,6 @@ path::operator/=(const path& __p)
     ++capacity; // Need to insert root-directory after root-name
 #endif
 
-  if (orig_type == _Type::_Multi)
-    {
-      const int curcap = _M_cmpts._M_impl->capacity();
-      if (capacity > curcap)
-	capacity = std::max(capacity, (int) (curcap * 1.5));
-    }
-
   _M_pathname.reserve(_M_pathname.length() + sep.length()
 		      + __p._M_pathname.length());

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-01-05 14:42 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-05 14:42 [gcc r14-6960] libstdc++: Avoid overflow when appending to std::filesystem::path Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).