[libcxx-commits] [PATCH] D90536: [libcxx/test] Fix UB when deleting D through a pointer to B.

Arthur O'Dwyer via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Sat Oct 31 11:06:49 PDT 2020


Quuxplusone created this revision.
Quuxplusone added a reviewer: ldionne.
Herald added a project: libc++.
Herald added a subscriber: libcxx-commits.
Herald added a reviewer: libc++.
Quuxplusone requested review of this revision.

After I apply Lénárd Szolnoki's proposal to disable implicit conversion of `default_delete<D>` to `default_delete<B>`, this particular `std::optional` test begins to fail:

  /llvm-project/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp:243:13: error: no viable overloaded '='
          opt = std::move(other);
          ~~~ ^ ~~~~~~~~~~~~~~~~
  /llvm-project/libcxx/include/optional:768:41: note: candidate function not viable: no known conversion from 'optional<unique_ptr<D, default_delete<D>>>' to 'optional<unique_ptr<B, default_delete<B>>>' for 1st argument
      _LIBCPP_INLINE_VISIBILITY optional& operator=(optional&&) = default;
                                          ^

I believe this is a true positive. The offending code in this test is circa line 243:

https://github.com/llvm/llvm-project/blob/master/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp#L240-L248

  {
      optional<std::unique_ptr<B>> opt;
      optional<std::unique_ptr<D>> other(new D());
      opt = std::move(other);
      assert(static_cast<bool>(opt) == true);
      assert(static_cast<bool>(other) == true);
      assert(opt->get() != nullptr);
      assert(other->get() == nullptr);
  }

At the closing curly brace, we destroy `opt`, which deletes `opt->get()` (a `B*` which dynamically points to a `D` object), which has UB because http://eel.is/c++draft/expr.delete#3 — am I right?

Giving `B` a virtual dtor fixes the UB without affecting anything else about this test.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D90536

Files:
  libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp


Index: libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp
===================================================================
--- libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp
+++ libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp
@@ -51,7 +51,7 @@
     Y2& operator=(const int&) { return *this; }
 };
 
-class B {};
+struct B { virtual ~B() = default; };
 class D : public B {};
 
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D90536.302104.patch
Type: text/x-patch
Size: 518 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20201031/8e1f2b27/attachment.bin>


More information about the libcxx-commits mailing list