Mój kod:

const int N = 1048569;
struct A { };
struct B : virtual public A {
    char space[N];
};
struct C : virtual public A {
    void foo() {};
};
struct D : public B, public C { };

D T;
int main() {
    T.foo();
    return 0;
}

Kiedy skompilowałem mój kod za pomocą -fsanitize=undefined, otrzymałem błąd wykonania poniżej:

a.cpp:13:10: runtime error: member call on address 0x560aead1e6a8 which does not point to an object of type 'C'
0x560aead1e6a8: note: object has a possibly invalid vptr: abs(offset to top) too big
 00 00 00 00  b0 dc c1 ea 0a 56 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00
              ^~~~~~~~~~~~~~~~~~~~~~~
              possibly invalid vptr

Program działa pomyślnie, jeśli nie użyję opcji -fsanitize=undefined.

Co więcej, jeśli ustawię wartość N do 1048568 (po prostu zmniejsza się o 1), program działa pomyślnie w obu przypadkach.

Zastanawiam się, czy to moja wina, czy to tylko dlatego, że fsanitize nie może poradzić sobie z takim dużym rozmiarem

0
Jacder Zhang 26 październik 2020, 07:05

1 odpowiedź

Najlepsza odpowiedź

Jest to arbitralny limit rozmiaru ustawiony przez nieokreślonego sanitizera Clanga's UntefinedBehaviour:

https://github.com/llvm/llvm-project/blob/5745eccef54ddd3caca2288d1d292A888B2281528B/compiler-rt/lib/ubsan/ubsan_type_hash.h#l55-l57.

/// A sanity check for Vtable. Offsets to top must be reasonably small
/// numbers (by absolute value). It's a weak check for Vtable corruption.
const int VptrMaxOffsetToTop = 1<<20;

"OFFSET-TOP" w Itanium ABI jest wartością ptrdiff_t w VTable dla każdego obiektu (i substancji podstawowej klasy), że po dodaniu do wskaźnika, daje wskaźnik do najbardziej pochodnego obiektu (typ ty new "lub zadeklarowany jako zmienna). To jest używane przez dynamic_cast<void*>(pointer_to_base). Ubsan spodziewa się, że będzie stosunkowo mały, ponieważ twoje zajęcia nie byłyby tak duże i przesunięte. Oznacza to jedyną okazję, że byłoby tak duże, jest to, że przypadkowo przekroczysz bufor i napisał do Vtable bezpośrednio.

Sposób na "naprawę" tego, jeśli naprawdę musisz zrobić, jest umieścić dużą klasę jako drugą klasę bazową, więc jego przesunięcie byłoby stosunkowo małe.

0
Artyer 26 październik 2020, 05:33