address sanitizer reports error when statically casting an invalid pointer

14,709

Shouldn't the pointer offset and therefore the correct resulting pointer value be known at compile time?

No, offset of virtually inherited class is not known at compile-time so compiler calculates it at runtime by accessing vtable.

Here's a simple example:

Base *foo(Derived *p) {
  return static_cast<Base*>(p);
}

It compiles to

movq    (%rdi), %rax     # Get vptr
addq    -24(%rax), %rdi  # Load offset of Base from vtable
movq    %rdi, %rax       # Return result
ret

ASan complains because you try to access some random memory address which causes a segfault.

Share:
14,709

Related videos on Youtube

nyronium
Author by

nyronium

Updated on June 04, 2022

Comments

  • nyronium
    nyronium almost 2 years

    When statically casting a Derived* in unallocated memory to a Base*, gcc's ASAN reports:

    ASAN:DEADLYSIGNAL
    =================================================================
    ==12829==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x563da3783776 bp 0x7ffde1670e50 sp 0x7ffde166d800 T0)
    ==12829==The signal is caused by a READ memory access.
    ==12829==Hint: address points to the zero page.
    

    For the test I used this setup:

    struct Base2 { int dummy; };
    struct Base { int dummy2; };
    struct Derived : public Base2, public virtual Base { };
    
    Derived* derived = (Derived*)0x1122334455667788; /* some pointer into non-allocated memory */
    Base* base = static_cast<Base*>(derived); /* ASAN fails here */
    

    Why does ASAN report an invalid read access here? Shouldn't the pointer offset and therefore the correct resulting pointer value be known at compile time?

    So why is this read access even necessary?

    • UKMonkey
      UKMonkey about 6 years
      Firstly, 0x1122334455667788 isn't what you think it is... It's more than likely truncated to 0x55667788 because it's taken as a conversion from an int. Secondly, the virtual isn't needed since you don't inherit Base multiple times. Finally, your error is about a null pointer access which you don't do in your snipit - so I don't think anyone can give you a reply that's meaningful
    • yugr
      yugr about 6 years
      @UKMonkey "which you don't do in your snipit" - he does, casting to virtually inherited class requires vtable access.
    • UKMonkey
      UKMonkey about 6 years
      @yugr and with no virtual functions, there is no vtable; which gives the null ptr access.... so infact the virtual inheritance is the cause of the problem. Interesting. (I try to avoid Diamond of Death situations; so my understanding of the impact of the virtual inheritance is a little fuzzy) Sounds like you've a nice answer there :)
    • yugr
      yugr about 6 years
      @UKMonkey I think you still need vtable if there are virtual base classes (even if no virtual functions) because compiler does not know their offsets until runtime. See my answer below for code which GCC 4.8 generates.