[libcxx-commits] [PATCH] D73134: Add invariant on <long string cap> >= __min_cap and change brittle __was_long cases

Martijn Vels via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jan 21 13:00:55 PST 2020


mvels created this revision.
Herald added subscribers: libcxx-commits, christof.
Herald added a project: libc++.
mvels added a reviewer: EricWF.
Herald added a reviewer: mclow.lists.

The partial inlining optimization for short strings could allocate strings at __min_cap size. Code in __grow_by assumed cap == __min_cap - 1 as proof that the input is an allocated long string leading to bad deallocation.

- add the invariant that no long string should have <= min_cap capacity
- use actual __is_long() for '__was_long' observation in __grow_byt logic

Combined these defend against both the (previously not expressed) invariant and its consequences.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D73134

Files:
  libcxx/include/string


Index: libcxx/include/string
===================================================================
--- libcxx/include/string
+++ libcxx/include/string
@@ -2144,6 +2144,7 @@
     size_type __ms = max_size();
     if (__delta_cap > __ms - __old_cap - 1)
         this->__throw_length_error();
+    bool __was_long = __is_long();
     pointer __old_p = __get_pointer();
     size_type __cap = __old_cap < __ms / 2 - __alignment ?
                           __recommend(_VSTD::max(__old_cap + __delta_cap, 2 * __old_cap)) :
@@ -2159,7 +2160,7 @@
     if (__sec_cp_sz != 0)
         traits_type::copy(_VSTD::__to_address(__p) + __n_copy + __n_add,
                           _VSTD::__to_address(__old_p) + __n_copy + __n_del, __sec_cp_sz);
-    if (__old_cap+1 != __min_cap)
+    if (__was_long)
         __alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1);
     __set_long_pointer(__p);
     __set_long_cap(__cap+1);
@@ -2176,6 +2177,7 @@
     size_type __ms = max_size();
     if (__delta_cap > __ms - __old_cap)
         this->__throw_length_error();
+    bool __was_long = __is_long();
     pointer __old_p = __get_pointer();
     size_type __cap = __old_cap < __ms / 2 - __alignment ?
                           __recommend(_VSTD::max(__old_cap + __delta_cap, 2 * __old_cap)) :
@@ -2190,7 +2192,7 @@
         traits_type::copy(_VSTD::__to_address(__p) + __n_copy + __n_add,
                           _VSTD::__to_address(__old_p) + __n_copy + __n_del,
                           __sec_cp_sz);
-    if (__old_cap+1 != __min_cap)
+    if (__was_long)
         __alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1);
     __set_long_pointer(__p);
     __set_long_cap(__cap+1);
@@ -3153,6 +3155,7 @@
 {
     if (__res_arg > max_size())
         this->__throw_length_error();
+    bool __was_long = __is_long();
     size_type __cap = capacity();
     size_type __sz = size();
     __res_arg = _VSTD::max(__res_arg, __sz);
@@ -3161,9 +3164,8 @@
     {
         pointer __new_data, __p;
         bool __was_long, __now_long;
-        if (__res_arg == __min_cap - 1)
+        if (__was_long)
         {
-            __was_long = true;
             __now_long = false;
             __new_data = __get_short_pointer();
             __p = __get_long_pointer();
@@ -3826,6 +3828,8 @@
         return false;
     if (capacity() < __min_cap - 1)
         return false;
+    if (__is_long() && capacity() < __min_cap)
+        return false;
     if (data() == 0)
         return false;
     if (data()[size()] != value_type(0))


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D73134.239415.patch
Type: text/x-patch
Size: 2525 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20200121/607ca116/attachment-0001.bin>


More information about the libcxx-commits mailing list