llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.92k stars 11.53k forks source link

LLDB sometimes can't determine the dynamic type of an object if the program is compiled with fPIC #50029

Open de9ccd5f-6521-4b39-ab30-f4e04ed39258 opened 3 years ago

de9ccd5f-6521-4b39-ab30-f4e04ed39258 commented 3 years ago
Bugzilla Link 50685
Version 12.0
OS Linux
Attachments The code in question, The preprocessed code
CC @JDevlieghere

Extended Description

If I compile the following code with fPIC or fPIE:

include <boost/asio/io_context.hpp>

include <boost/asio/strand.hpp>

void foo(boost::asio::io_context& context) { boost::asio::io_context::strand s{context}; }

struct Base { virtual ~Base() {} };

struct Derived: Base { Derived(int zzz) : zzz(zzz) {}

int zzz = 0;

};

int main() { Derived d{123}; Base* b = &d;

return 0;

}

and run it in lldb, "print b" will print: (Base *) $0 = 0x00007fffffffdc58

But if I compile it without fPIC/fPIE, or modify the code slightly, e.g. by commenting out the unused function "foo", I get the expected output: (Derived *) $0 = 0x00007fffffffdc58

The behaviour doesn't depend on the compiler; I tried clang 11.0 and gcc-10.2 and the result was the same.

Since the code depends on boost, I'm attaching the preprocessed version too.

I compile it as follows: $ clang++ -g -fPIC test_preproc_clang.cpp -o test -lpthread

Clang version: Ubuntu clang version 11.0.0-2

LLDB version: lldb version 12.0.0 (git@github.com:llvm/llvm-project.git revision d28af7c654d8db0b68c175db5ce212d74fb5e9bc) clang revision d28af7c654d8db0b68c175db5ce212d74fb5e9bc llvm revision d28af7c654d8db0b68c175db5ce212d74fb5e9bc

boost version: 1.73.0

de9ccd5f-6521-4b39-ab30-f4e04ed39258 commented 2 years ago

I've stumbled across a simpler case that doesn't require boost or fPIC/fPIE. Here Derived is a template that is instantiated with 2 structs, one global and another one local to a function. In the first case the dynamic type is detected correctly, in the second case it is not.

test.cpp

struct Base { virtual ~Base() {} };

template struct Derived: Base { };

struct OuterFoo { };

int main() { struct InnerFoo { };

Derived<OuterFoo> od;
Base* ob = &od;

Derived<InnerFoo> id;
Base* ib = &id;

return 0;

}

Command line:

$ clang++ -g test.cpp -o test $ lldb-12 -f test -o "b 27" -o "run" -o "p ob" -o "p ib" -o quit ... Process 2849427 launched: '/home/brd/work/misc/tests/lldb_base_class_issue2/test' (x86_64) (lldb) p ob (Derived ) $0 = 0x00007fffffffda70 (lldb) p ib (Base ) $1 = 0x00007fffffffda60

Symbol table:

$ lldb-12 -f test -o "image dump symtab" -o quit | grep Foo [ 11] 12 Code 0x0000000000401190 0x0000000000000034 0x00000002 Derived::Derived() [ 12] 13 Code 0x00000000004011f0 0x0000000000000028 0x00000002 Derived::~Derived() [ 13] 14 Code 0x00000000004011d0 0x000000000000001b 0x00000002 Derived::~Derived() [ 14] 15 Data 0x00000000004020d0 0x0000000000000018 0x00000001 typeinfo for Derived [ 15] 16 Data 0x00000000004020b0 0x000000000000001b 0x00000001 typeinfo name for Derived [ 16] 17 Data 0x0000000000402090 0x0000000000000020 0x00000001 vtable for Derived [ 24] 26 Code 0x0000000000401260 0x000000000000001b 0x00000022 Derived::~Derived() [ 26] 28 Data 0x0000000000402028 0x0000000000000014 0x00000021 typeinfo name for Derived [ 29] 31 Code 0x0000000000401220 0x0000000000000034 0x00000022 Derived::Derived() [ 43] 45 Code 0x00000000004012a0 0x0000000000000028 0x00000022 Derived::~Derived() [ 51] 53 Data 0x0000000000402058 0x0000000000000018 0x00000021 typeinfo for Derived [ 55] 57 Data 0x0000000000402008 0x0000000000000020 0x00000021 vtable for Derived

Versions:

$ clang++ --version Ubuntu clang version 12.0.0-3ubuntu1~21.04.2 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin

$ lldb-12 --version lldb version 12.0.0

de9ccd5f-6521-4b39-ab30-f4e04ed39258 commented 3 years ago

vtable seems to be present:

(lldb) image dump symtab ... [ 329] 331 Data 0x0000000000410d98 0x0000000000410d98 0x0000000000000020 0x00000021 vtable for Base ... [ 529] 531 Data 0x0000000000410d50 0x0000000000410d50 0x0000000000000020 0x00000021 vtable for Derived ...

jimingham commented 3 years ago

lldb depends on there being a vtable symbol for the classes. Can you dump the symbol table (e.g. "image dump symtab" in lldb) and see if there is a vtable symbol.

If there is and we're not matching it up this the object, then that's some kind of lldb bug. If it is not present, lldb can't do this detection, and to resolve the issue you will have to figure out what it takes to get the compilation not to elide that symbol.