From 097f1f4a98222b2fa379093b5c012140d6b7ed8b Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 16 Mar 2021 02:54:30 -0400 Subject: [PATCH 1/4] Be more precise about array cookies; issue #119. --- abi.html | 162 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 95 insertions(+), 67 deletions(-) diff --git a/abi.html b/abi.html index 2e8dd75b..b9eb5abf 100644 --- a/abi.html +++ b/abi.html @@ -2111,86 +2111,114 @@

2.6.4 Construction Virtual Table entries 2.7 Array Operator new Cookies

-When operator new is used to create a new array, -a cookie is usually stored to remember the allocated length -(number of array elements) -so that it can be deallocated correctly. +When a new expression is used to create a new array, +a "cookie" must sometimes be added to the allocation. A cookie is +a header on the array allocation, preceding the array elements, +which stores the number of array elements that were allocated.

-Specifically: +Let T be the element type of the allocated array, +looking through all levels of nested array. +Whether a cookie is required is determined as follows: +

- -

- These rules have the following consequences: -

-
+

If a cookie is required, the allocation is adjusted as follows: +

-Given the above, the following is pseudocode for processing -new(ARGS) T[n]: -

-  if T has a trivial destructor (C++ standard, 12.4/3)
-    padding = 0
-  else if we're using ::operator new[](size_t, void*)
-    padding = 0
-  else
-    padding = max(sizeof(size_t), alignof(T))
-
-  p = operator new[](n * sizeof(T) + padding, ARGS)
-  p1 = (T*) ( (char *)p + padding )
-
-  if padding > 0
-    *( (size_t *)p1 - 1) = n
-
-  for i = [0, n)
-    create a T, using the default constructor, at p1[i]
-
-  return p1
-
+A delete[] expression must also compensate for the +possible presence of an array cookie: +


From dbab9d58d430e66d050c05ba12ebc3b90c1e9087 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 16 Mar 2021 18:09:46 -0400 Subject: [PATCH 2/4] Updates from review --- abi.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/abi.html b/abi.html index b9eb5abf..b7f033b7 100644 --- a/abi.html +++ b/abi.html @@ -2156,9 +2156,9 @@

2.7 Array Operator new Cookies Let count be the total number of objects of type - T that will be created, scaled appropriately by the - bounds of any nested arrays. This is the value that will be stored - in the cookie. For example, given the expresssion + T that will be created (including any scaling + necessary for nested arrays). This is the value that will be + stored in the cookie. For example, given the expresssion new T[len][7][5], count is len * 7 * 5. @@ -2167,6 +2167,9 @@

2.7 Array Operator new Cookies T has a new-extended alignment, and so the presence of a cookie does not affect the choice of allocation or deallocation function. + However, it does affect the value of type std::align_val_t + that must be passed when using an allocation or deallocation + function with such an argument.
  • Let prefix_size be max(sizeof(cookie_t), align). From 04309fd93680257733718d8bf884d732dc63dae0 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 9 May 2023 11:15:29 -0600 Subject: [PATCH 3/4] Don't incorporate cookie alignment into new[] allocations Per discussion with @zygoloid, the standard does not permit cookie alignment to be factored into allocations, either by changing the resolution of operator new[] or changing the `std::align_val_t` argument. We could ask for this to be changed, but it's not clear that there's any reasonable solution for class-specific allocators that don't take an explicit alignment, which it seems reasonable to say should be allowed to return something based on the alignment of the class. Given that, the only reasonable decision is to not always align the cookie. We should still be able to assume it's aligned in common cases. --- abi.html | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/abi.html b/abi.html index b7f033b7..33013ea7 100644 --- a/abi.html +++ b/abi.html @@ -2131,10 +2131,11 @@

    2.7 Array Operator new Cookies
  • T has a non-trivial destructor, or else -
  • there is an unambiguous usual array deallocation function - for T (as would be found for the delete[] - operator on an operand of type T*), and that - function takes a size_t argument. +
  • there is an unambiguous usual class-specific array deallocation + function for T (as would be found for the + delete[] operator on an operand of type + T*), and that function takes a size_t + argument.

    This operator must be looked up as if for a delete[] without a :: prefix, even if the new @@ -2162,14 +2163,16 @@

    2.7 Array Operator new Cookies new T[len][7][5], count is len * 7 * 5. -
  • Let align be max(alignof(cookie_t), alignof(T)). - This is the alignment of the allocation. Note that this is - a new-extended alignment if and only if T has a - new-extended alignment, and so the presence of a cookie does not - affect the choice of allocation or deallocation function. - However, it does affect the value of type std::align_val_t - that must be passed when using an allocation or deallocation - function with such an argument. +
  • Let align be alignof(T). + This is the alignment of the allocation. Note that this does + not include the alignment of cookie_t. The standard + permits array allocation to request a larger allocation to + accommodate cookies, but not a more-aligned allocation. Adding a + cookie is also not permitted to change the choice of allocation or + deallocation function, which it otherwise could in uncommon situations + where cookie_t has a new-extended alignment. As a + result, the implementation may be required to load and store the + cookie with less than its natural alignment.
  • Let prefix_size be max(sizeof(cookie_t), align). @@ -2182,8 +2185,12 @@

    2.7 Array Operator new Cookies new expression. -
  • The cookie is stored at offset prefix_size - sizeof(cookie_t) - from the start of the allocation. +
  • In the standard ABI, padding is added before the cookie, so the + cookie is stored at offset prefix_size - sizeof(cookie_t) + from the start of the allocation. However, in some variant ABIs, + padding is added after the cookie, which is stored at the start of + the allocation. In either case, the contents of any padding bytes + are undefined. @@ -2212,7 +2219,8 @@

    2.7 Array Operator new Cookies If a cookie is required, it is found at offset -sizeof(cookie_t) from ptr, and the original allocation is found at offset -prefix_size - from ptr. + from ptr. In variant ABIs that pad after the cookie, + the cookie will be at offset -prefix_size.
  • If T has a non-trivial destructor, the value of count stored in the cookie is the number of From 55dd1e5a153900d626f635357b6830a9b0bf4662 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 9 May 2023 11:17:58 -0600 Subject: [PATCH 4/4] Apply one of Richard's suggestions that I missed in my last commit. Co-authored-by: Richard Smith --- abi.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abi.html b/abi.html index 33013ea7..635f7c47 100644 --- a/abi.html +++ b/abi.html @@ -2144,7 +2144,7 @@

    2.7 Array Operator new Cookies delete, as it is not always ill-defined under the standard to mix the use of global and class-scoped allocation and deallocation functions. (For example, a - class-scoped deallocation function might delegate to the + class-specific deallocation function might delegate to the corresponding global deallocation function.)