<html>
<head>
<base href="https://llvm.org/bugs/" />
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW --- - ~unique_ptr() should not set stored pointer to null"
href="https://llvm.org/bugs/show_bug.cgi?id=24907">24907</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>~unique_ptr() should not set stored pointer to null
</td>
</tr>
<tr>
<th>Product</th>
<td>libc++
</td>
</tr>
<tr>
<th>Version</th>
<td>unspecified
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>All
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>normal
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>All Bugs
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedclangbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>dcheng@google.com
</td>
</tr>
<tr>
<th>CC</th>
<td>llvm-bugs@lists.llvm.org, mclow.lists@gmail.com
</td>
</tr>
<tr>
<th>Classification</th>
<td>Unclassified
</td>
</tr></table>
<p>
<div>
<pre>Currently, libc++ nulls out the stored pointer when a unique_ptr is destroyed.
Unfortunately, this is inconsistent with how libstdc++ and MSVC's standard
library. For compatibility, I believe libc++ should match the behavior of the
other standard libraries.
Copying and pasting from gromer's original report at
<a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54351">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54351</a>
libstdc++'s unique_ptr destructor is currently implemented as:
~unique_ptr() noexcept { reset(); }
This has the effect of resetting the stored pointer to null, and then invoking
the deleter on the formerly-stored pointer. I believe this is inconsistent with
the language standard, which specifies the destructor as "If get() == nullptr
there are no effects. Otherwise get_deleter()(get())." (note no mention of any
side effects on the value of the stored pointer). This is a problem because
this implementation will break code that (legitimately, AFAICT) relies on being
able to continue to invoke operations on the scoped_ptr while the destructor is
executing.
The fix is to reimplement the destructor (in both the base template and the
array specialization) as
~unique_ptr() noexcept {
if (__p != pointer())
get_deleter()(__p);
}
If the intent is to zero out __p to help catch use-after-destruction errors, I
believe it would be permissible to set __p to null after the call to
get_deleter(), because at that point the change would no longer be visible to
conforming code.
To make this concrete, here's an example: the following program prints "bad"
under libstdc++, but I believe a standard-conforming implementation is required
to print "good":
=============================
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
using std::unique_ptr;
struct A;
struct B {
unique_ptr<A> a;
};
struct A {
B* b;
~A() {
if (b->a == nullptr) {
cout << "bad" << endl;
} else {
cout << "good" << endl;
}
}
};
int main(int argc, char** argv) {
B b;
b.a.reset(new A);
b.a->b = &b;
}
===============================
As a point of comparison, MSVC++ 2010 prints "good" on this example program.</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>