c++: ICE with -fsanitize=vptr and constexpr dynamic_cast [PR98103]
authorMarek Polacek <polacek@redhat.com>
Wed, 2 Dec 2020 19:33:13 +0000 (14:33 -0500)
committerMarek Polacek <polacek@redhat.com>
Tue, 8 Dec 2020 22:26:37 +0000 (17:26 -0500)
-fsanitize=vptr initializes all vtable pointers to null so that it can
catch invalid calls; see cp_ubsan_maybe_initialize_vtbl_ptrs.  That
means that evaluating a vtable reference can produce a null pointer
in this mode, so cxx_eval_dynamic_cast_fn should check that and give
and error.

gcc/cp/ChangeLog:

PR c++/98103
* constexpr.c (cxx_eval_dynamic_cast_fn): If the evaluating of vtable
yields a null pointer, give an error and return.  Use objtype.

gcc/testsuite/ChangeLog:

PR c++/98103
* g++.dg/ubsan/vptr-18.C: New test.

gcc/cp/constexpr.c
gcc/testsuite/g++.dg/ubsan/vptr-18.C [new file with mode: 0644]

index 2ef6de83830f185b75c75fc369f562efba0c88d6..b6f3e6e7a3143b8ed71804b76957191039449d53 100644 (file)
@@ -1998,11 +1998,20 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
      to the object under construction or destruction, this object is
      considered to be a most derived object that has the type of the
      constructor or destructor's class.  */
-  tree vtable = build_vfield_ref (obj, TREE_TYPE (obj));
+  tree vtable = build_vfield_ref (obj, objtype);
   vtable = cxx_eval_constant_expression (ctx, vtable, /*lval*/false,
                                         non_constant_p, overflow_p);
   if (*non_constant_p)
     return call;
+  /* With -fsanitize=vptr, we initialize all vtable pointers to null,
+     so it's possible that we got a null pointer now.  */
+  if (integer_zerop (vtable))
+    {
+      if (!ctx->quiet)
+       error_at (loc, "virtual table pointer is used uninitialized");
+      *non_constant_p = true;
+      return integer_zero_node;
+    }
   /* VTABLE will be &_ZTV1A + 16 or similar, get _ZTV1A.  */
   vtable = extract_obj_from_addr_offset (vtable);
   const tree mdtype = DECL_CONTEXT (vtable);
diff --git a/gcc/testsuite/g++.dg/ubsan/vptr-18.C b/gcc/testsuite/g++.dg/ubsan/vptr-18.C
new file mode 100644 (file)
index 0000000..cd2ca0a
--- /dev/null
@@ -0,0 +1,25 @@
+// PR c++/98103
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-fsanitize=vptr -fno-sanitize-recover=vptr" }
+// Modified constexpr-dynamic17.C.
+
+struct V {
+  virtual void f();
+};
+
+struct A : V { };
+
+struct B : V {
+  constexpr B(V*, A*);
+};
+
+struct D : B, A {
+  constexpr D() : B((A*)this, this) { }
+};
+
+constexpr B::B(V* v, A* a)
+{
+  dynamic_cast<B*>(a); // { dg-error "uninitialized" }
+}
+
+constexpr D d;