[llvm-bugs] [Bug 24907] New: ~unique_ptr() should not set stored pointer to null

via llvm-bugs llvm-bugs at lists.llvm.org
Tue Sep 22 00:43:10 PDT 2015


https://llvm.org/bugs/show_bug.cgi?id=24907

            Bug ID: 24907
           Summary: ~unique_ptr() should not set stored pointer to null
           Product: libc++
           Version: unspecified
          Hardware: PC
                OS: All
            Status: NEW
          Severity: normal
          Priority: P
         Component: All Bugs
          Assignee: unassignedclangbugs at nondot.org
          Reporter: dcheng at google.com
                CC: llvm-bugs at lists.llvm.org, mclow.lists at gmail.com
    Classification: Unclassified

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
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54351

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.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20150922/92814e61/attachment-0001.html>


More information about the llvm-bugs mailing list