<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 206: operator new(size_t, nothrow) may become unlinked to ordinary operator new if ordinary version replaced</title>
<meta property="og:title" content="Issue 206: operator new(size_t, nothrow) may become unlinked to ordinary operator new if ordinary version replaced">
<meta property="og:description" content="C++ library issue. Status: CD1">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue206.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#CD1">CD1</a> status.</em></p>
<h3 id="206"><a href="lwg-defects.html#206">206</a>. operator new(size_t, nothrow) may become unlinked to ordinary operator new if ordinary version replaced</h3>
<p><b>Section:</b> 17.6.3.2 <a href="https://wg21.link/new.delete.single">[new.delete.single]</a> <b>Status:</b> <a href="lwg-active.html#CD1">CD1</a>
 <b>Submitter:</b> Howard Hinnant <b>Opened:</b> 1999-08-29 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View other</b> <a href="lwg-index-open.html#new.delete.single">active issues</a> in [new.delete.single].</p>
<p><b>View all other</b> <a href="lwg-index.html#new.delete.single">issues</a> in [new.delete.single].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#CD1">CD1</a> status.</p>
<p><b>Discussion:</b></p>
<p>As specified, the implementation of the nothrow version of operator
new does not necessarily call the ordinary operator new, but may
instead simply call the same underlying allocator and return a null
pointer instead of throwing an exception in case of failure.</p>

<p>Such an implementation breaks code that replaces the ordinary
version of new, but not the nothrow version. If the ordinary version
of new/delete is replaced, and if the replaced delete is not
compatible with pointers returned from the library versions of new,
then when the replaced delete receives a pointer allocated by the
library new(nothrow), crash follows.</p>

<p>The fix appears to be that the lib version of new(nothrow) must
call the ordinary new. Thus when the ordinary new gets replaced, the
lib version will call the replaced ordinary new and things will
continue to work.</p>

<p>An alternative would be to have the ordinary new call
new(nothrow). This seems sub-optimal to me as the ordinary version of
new is the version most commonly replaced in practice. So one would
still need to replace both ordinary and nothrow versions if one wanted
to replace the ordinary version.</p>

<p>Another alternative is to put in clear text that if one version is
replaced, then the other must also be replaced to maintain
compatibility. Then the proposed resolution below would just be a
quality of implementation issue. There is already such text in
paragraph 7 (under the new(nothrow) version). But this nuance is
easily missed if one reads only the paragraphs relating to the
ordinary new.</p>

<p>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2158.html">N2158</a>
has been written explaining the rationale for the proposed resolution below.
</p>



<p id="res-206"><b>Proposed resolution:</b></p>
<p>
Change 18.5.1.1 [new.delete.single]:
</p>

<blockquote>
<pre>
void* operator new(std::size_t <i>size</i>, const std::nothrow_t&amp;) throw();
</pre>
<blockquote>
<p>
-5- <i>Effects:</i> Same as above, except that it is called by a placement
version of a <i>new-expression</i> when a C++ program prefers a null pointer result as
an error indication, instead of a <code>bad_alloc</code> exception.
</p>

<p>
-6- <i>Replaceable:</i> a C++ program may define a function with this function
signature that displaces the default version defined by the C++ Standard
library.
</p>

<p>
-7- <i>Required behavior:</i> Return a non-null pointer to suitably aligned
storage (3.7.4), or else return a null pointer. This nothrow version of operator
new returns a pointer obtained as if acquired from the <ins>(possibly
replaced)</ins> ordinary version. This requirement is binding on a replacement
version of this function.
</p>

<p>
-8- <i>Default behavior:</i>
</p>
<ul>
<li><ins>
Calls <code>operator new(<i>size</i>)</code>.
</ins></li>
<li><ins>
If the call to <code>operator new(<i>size</i>)</code> returns normally, returns
the result of that call, else
</ins></li>
<li><ins>
if the call to <code>operator new(<i>size</i>)</code> throws an exception, returns
a null pointer.
</ins></li>
<li><del>
Executes a loop: Within the loop, the function first attempts to allocate the
requested storage. Whether the attempt involves a call to the Standard C library
function <code>malloc</code> is unspecified.
</del></li>
<li><del>
Returns a pointer to the allocated storage if the attempt is successful.
Otherwise, if the last argument to <code>set_new_handler()</code> was a null
pointer, return a null pointer.
</del></li>
<li><del>
Otherwise, the function calls the current <i>new_handler</i> (18.5.2.2). If the
called function returns, the loop repeats.
</del></li>
<li><del>
The loop terminates when an attempt to allocate the requested storage is
successful or when a called <i>new_handler</i> function does not return. If the
called <i>new_handler</i> function terminates by throwing a <code>bad_alloc
exception</code>, the function returns a null pointer.
</del></li>
</ul>
<p>
-9- [<i>Example:</i>
</p>
<blockquote><pre>
T* p1 = new T;                 <i>// throws bad_alloc if it fails</i>
T* p2 = new(nothrow) T;        <i>// returns 0 if it fails</i>
</pre></blockquote>
<p>
--<i>end example</i>]
</p>
</blockquote>

<pre>
void operator delete(void* <i>ptr</i>) throw();
<del>void operator delete(void* <i>ptr</i>, const std::nothrow_t&amp;) throw();</del>
</pre>

<blockquote>
<p>
-10- <i>Effects:</i> The <i>deallocation function</i> (3.7.4.2) called by a
<i>delete-expression</i> to render the value of <code><i>ptr</i></code> invalid.
</p>
<p>
-11- <i>Replaceable:</i> a C++ program may define a function with this function
signature that displaces the default version defined by the C++ Standard
library.
</p>
<p>
-12- <i>Requires:</i> the value of <code><i>ptr</i></code> is null or the value
returned by an earlier call to the <del>default</del> <ins>(possibly
replaced)</ins> <code>operator new(std::size_t)</code> or <code>operator
new(std::size_t, const std::nothrow_t&amp;)</code>.
</p>
<p>
-13- <i>Default behavior:</i>
</p>
<ul>
<li>
For a null value of <code><i>ptr</i></code>, do nothing.
</li>
<li>
Any other value of <code><i>ptr</i></code> shall be a value returned earlier by a
call to the default <code>operator new</code>, which was not invalidated by an
intervening call to <code>operator delete(void*)</code> (17.4.3.7). For such a
non-null value of <code><i>ptr</i></code>, reclaims storage allocated by the earlier
call to the default <code>operator new</code>.
</li>
</ul>
<p>
-14- <i>Remarks:</i>  It is unspecified under what conditions part or all of
such reclaimed storage is allocated by a subsequent call to <code>operator
new</code> or any of <code>calloc</code>, <code>malloc</code>, or <code>realloc</code>,
declared in <code>&lt;cstdlib&gt;</code>.
</p>
</blockquote>

<pre>
<ins>void operator delete(void* <i>ptr</i>, const std::nothrow_t&amp;) throw();</ins>
</pre>

<blockquote>
<p><ins>
-15- <i>Effects:</i> Same as above, except that it is called by the
implementation when an exception propagates from a nothrow placement version
of the <i>new-expression</i> (i.e. when the constructor throws an exception).
</ins></p>
<p><ins>
-16- <i>Replaceable:</i> a C++ program may define a function with this function
signature that displaces the default version defined by the C++ Standard
library.
</ins></p>
<p><ins>
-17- <i>Requires:</i> the value of <code><i>ptr</i></code> is null or the
value returned by an earlier call to the (possibly replaced) <code>operator
new(std::size_t)</code> or <code>operator new(std::size_t, const
std::nothrow_t&amp;)</code>. </ins></p>
<p><ins>
-18- <i>Default behavior:</i> Calls <code>operator delete(<i>ptr</i>)</code>.
</ins></p>
</blockquote>

</blockquote>

<p>
Change 18.5.1.2 [new.delete.array]
</p>

<blockquote>
<pre>
void* operator new[](std::size_t <i>size</i>, const std::nothrow_t&amp;) throw();
</pre>

<blockquote>
<p>
-5- <i>Effects:</i> Same as above, except that it is called by a placement
version of a <i>new-expression</i> when a C++ program prefers a null pointer result as
an error indication, instead of a <code>bad_alloc</code> exception.
</p>

<p>
-6- <i>Replaceable:</i>  a C++ program can define a function with this function
signature that displaces the default version defined by the C++ Standard
library.
</p>

<p>
-7- <i>Required behavior:</i> <del>Same as for operator <code>new(std::size_t,
const std::nothrow_t&amp;)</code>. This nothrow version of operator <code>new[]</code>
returns a pointer obtained as if acquired from the ordinary version.</del>
<ins>Return a non-null pointer to suitably aligned storage (3.7.4), or else
return a null pointer. This nothrow version of operator new returns a pointer
obtained as if acquired from the (possibly replaced) <code>operator
new[](std::size_t <i>size</i>)</code>. This requirement is binding on a
replacement version of this function.</ins>
</p>

<p>
-8- <i>Default behavior:</i> <del>Returns <code>operator new(<i>size</i>,
nothrow)</code>.</del>
</p>

<ul>
<li><ins>
Calls <code>operator new[](<i>size</i>)</code>.
</ins></li>
<li><ins>
If the call to <code>operator new[](<i>size</i>)</code> returns normally, returns
the result of that call, else
</ins></li>
<li><ins>
if the call to <code>operator new[](<i>size</i>)</code> throws an exception, returns
a null pointer.
</ins></li>
</ul>
</blockquote>

<pre>
void operator delete[](void* <i>ptr</i>) throw(); 
void operator delete[](void* <i>ptr</i>, const std::nothrow_t&amp;) throw();
</pre>

<blockquote>
<p>
-9- <i>Effects:</i> The <i>deallocation function</i> (3.7.4.2) called by the
array form of a <i>delete-expression</i> to render the value of
<code><i>ptr</i></code> invalid.
</p>

<p>
-10- <i>Replaceable:</i> a C++ program can define a function with this function
signature that displaces the default version defined by the C++ Standard
library.
</p>

<p>
-11- <i>Requires:</i> the value of
<code><i>ptr</i></code> is null or the value returned by an earlier call to
<code>operator new[](std::size_t)</code> or <code>operator new[](std::size_t, const
std::nothrow_t&amp;)</code>.
</p>

<p>
-12- <i>Default behavior:</i> Calls <code>operator delete(<i>ptr</i>)</code> or
<code>operator delete<ins>[]</ins>(<i>ptr</i><del>, std::nothrow</del>)</code> respectively.
</p>
</blockquote>

</blockquote>



<p><b>Rationale:</b></p>
<p>Yes, they may become unlinked, and that is by design. If a user
replaces one, the user should also replace the other.</p>

<p><i>[
Reopened due to a gcc conversation between Howard, Martin and Gaby.  Forwarding
or not is visible behavior to the client and it would be useful for the client
to know which behavior it could depend on.
]</i></p>


<p><i>[
Batavia: Robert voiced serious reservations about backwards compatibility for
his customers.
]</i></p>






</body>
</html>
