[Bug c++/87697] Casting a base class to derived gives no warning

redi at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Tue Oct 23 09:31:00 GMT 2018


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

--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to jynelson from comment #0)
> Casting a base class to a derived class gives no warning, even with -Wall
> -Werror enabled. I've been told on IRC that this sort of cast is undefined
> behaviour according to spec if neither class is virtual.

It has nothing to do with whether anything is virtual or not. The relevant
standard wording is:

   If the object of type “cv1 B” is actually a base class subobject of an
   object of type D, the result refers to the enclosing object of type D.
   Otherwise, the behavior is undefined.

Since the pointer returned by 'new c1' does not point to a base class subobject
of an object of type derived, the behaviour is undefined.

> If that is the
> case, it would be nice to have a warning.

It's only possible to warn when the compiler can statically prove that the
pointer really isn't pointing to a derived. That's possible in your example
because it was created right there by the 'new c1' expression, but that is a
very silly thing to do and surely nobody does it in real code. Generally a
function just gets passed a pointer to a base class, and can't see its
construction, so can't tell if the cast is valid or not.

> If that isn't the case, there are several more questions that arise, like
> `why does c1 have access to c2` and `why can the const value c2::x be
> accessed without be initialized`?

It doesn't, because there's no c2 object constructed. Obviously the code is
silly and broken.

I don't think a compiler warning would be worthwhile, because it would only
warn about code which is obviously wrong by inspection i.e. which should be
caught by the most cursory code review.

The general case can be diagnosed through runtime instrumentation but
-fsanitize=undefined only gives a runtime error for an invalid static_cast
involving polymorphic types (because the type identification is linked to the
vtable).

-fsanitize=address does diagnose that accessing members of c2 performs an
out-of-bounds read:

constructor 1
=================================================================
==16923==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x602000000010 at pc 0x000000400b03 bp 0x7ffc6744ca60 sp 0x7ffc6744ca58
READ of size 4 at 0x602000000010 thread T0
    #0 0x400b02 in c2::foo() /tmp/inh.cc:14
    #1 0x400a41 in main /tmp/inh.cc:30
    #2 0x7f1f0cb87fe9 in __libc_start_main ../csu/libc-start.c:308
    #3 0x400969 in _start (/tmp/a.out+0x400969)

0x602000000011 is located 0 bytes to the right of 1-byte region
[0x602000000010,0x602000000011)
allocated by thread T0 here:
    #0 0x7f1f0d8f04f0 in operator new(unsigned long)
/home/jwakely/src/gcc/gcc/libsanitizer/asan/asan_new_delete.cc:90
    #1 0x400a26 in main /tmp/inh.cc:27
    #2 0x7f1f0cb87fe9 in __libc_start_main ../csu/libc-start.c:308

SUMMARY: AddressSanitizer: heap-buffer-overflow /tmp/inh.cc:14 in c2::foo()
Shadow bytes around the buggy address:
  0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa[01]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==16923==ABORTING


More information about the Gcc-bugs mailing list