https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99074

Martin Sebor <msebor at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |diagnostic
   Last reconfirmed|                            |2021-02-12
                 CC|                            |msebor at gcc dot gnu.org
         Resolution|INVALID                     |---
   Target Milestone|---                         |12.0
             Status|RESOLVED                    |ASSIGNED
     Ever confirmed|0                           |1
           Assignee|unassigned at gcc dot gnu.org      |msebor at gcc dot 
gnu.org

--- Comment #2 from Martin Sebor <msebor at gcc dot gnu.org> ---
True, it's undefined, and regrettably not caught by -Wnonnull.  The warning
runs both too early (in the FE) and too late (in CCP).  But can we do better
than simply crashing?  Clang can, as can ICC (no crash there).  It seems to me
the call to __dynamic_cast with the null pointer could be intercepted.  At
compile-time, GCC could warn, and at runtime, the call could return null.  The
following is a proof of concept that does that:

$ /build/gcc-master/gcc/xg++ -B /build/gcc-master/gcc -nostdinc++ -L
/build/gcc-master/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs -O2 -Wall
pr99074.C &&
LD_LIBRARY_PATH=/build/gcc-master/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs
./a.out
In member function ‘Object* AbstractBase::_to_object()’,
    inlined from ‘int main()’ at pr99074.C:24:39:
pr99074.C:12:35: warning: argument 1 null where non-null expected [-Wnonnull]
   12 |     Object* _to_object() { return dynamic_cast<Object*>(this); }
      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
pr99074.C: In function ‘int main()’:
pr99074.C:12:61: note: in a call to function ‘void* __dynamic_cast(const void*,
const __cxxabiv1::__class_type_info*, const __cxxabiv1::__class_type_info*,
long int)’ declared ‘nonnull’
   12 |     Object* _to_object() { return dynamic_cast<Object*>(this); }
      |                                                             ^
object is: (nil)

Let me confirm this bug and propose the change below.

diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index b41d95469c6..c54e431de31 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stor-layout.h"
 #include "c-family/c-pragma.h"
 #include "gcc-rich-location.h"
+#include "attribs.h"

 /* C++ returns type information to the user in struct type_info
    objects. We also use type information to implement dynamic_cast and
@@ -767,6 +768,10 @@ build_dynamic_cast_1 (location_t loc, tree type, tree
expr,
              dcast_fn = (build_library_fn_ptr
                          (fn_name, fn_type, ECF_LEAF | ECF_PURE |
ECF_NOTHROW));
              pop_abi_namespace (flags);
+
+             tree attr = tree_cons (get_identifier ("nonnull"), 0, 0);
+             decl_attributes (&dcast_fn, attr, 0);
+
              dynamic_cast_node = dcast_fn;
            }
          result = build_cxx_call (dcast_fn, 4, elems, complain);
diff --git a/libstdc++-v3/libsupc++/dyncast.cc
b/libstdc++-v3/libsupc++/dyncast.cc
index b7d98495ad3..6e9d81b312d 100644
--- a/libstdc++-v3/libsupc++/dyncast.cc
+++ b/libstdc++-v3/libsupc++/dyncast.cc
@@ -47,6 +47,8 @@ __dynamic_cast (const void *src_ptr,    // object started
from
                 const __class_type_info *dst_type, // desired target type
                 ptrdiff_t src2dst) // how src and dst are related
   {
+  if (!src_ptr)
+    return NULL;
   const void *vtable = *static_cast <const void *const *> (src_ptr);
   const vtable_prefix *prefix =
     (adjust_pointer <vtable_prefix>

Reply via email to