llvm / llvm-project

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

LLDB does not respect alignment on typedefs #90958

Open labath opened 2 weeks ago

labath commented 2 weeks ago

c++11 alignas does not work on typedefs, but __attribute__((aligned)) (gcc) and __declspec(align) (msvc) do.

Clang correctly emits DW_AT_alignment for these types, but lldb just ignores it.

I don't know of anything specific broken by this, but one can imagine a failure where lldb constructs (in an expression) an under-aligned object and passes is to a inferior function which expects it to be aligned (and explodes when it isn't).

Fixing this is somewhat tricky because lldb constructs ASTs for typedefs lazily, which means it's necessary to store the alignment in the Type::m_payload field. Currently all bits of the (32-bit) field are taken, so we may need to increase the size of that field or reduce the number of bits used by the clang module id.

llvmbot commented 2 weeks ago

@llvm/issue-subscribers-lldb

Author: Pavel Labath (labath)

c++11 `alignas` does not work on typedefs, but `__attribute__((aligned))` (gcc) and `__declspec(align)` (msvc) do. Clang correctly emits DW_AT_alignment for these types, but lldb just ignores it. I don't know of anything specific broken by this, but one can imagine a failure where lldb constructs (in an expression) an under-aligned object and passes is to a inferior function which expects it to be aligned (and explodes when it isn't). Fixing this is somewhat tricky because lldb constructs ASTs for typedefs lazily, which means it's necessary to store the alignment in the Type::m_payload field. Currently all bits of the (32-bit) field are taken, so we may need to increase the size of that field or reduce the number of bits used by the clang module id.
labath commented 1 week ago

I today, I have encountered "lazy typedefs" working from a different angle: Their laziness means that its unable to reference them from an expression until something causes them to be materialized:

$ cat /tmp/a.cc
struct X {
  typedef int InX;
};

X a;
X::InX b;

int main() {
  return b;
}
$ g++ /tmp/a.cc -g -o /tmp/a.out
$ bin/lldb /tmp/a.out
(lldb) target create "/tmp/a.out"
Current executable set to '/tmp/a.out' (x86_64).
(lldb) expr -- X::InX a; a
error: <user expression 0>:1:4: no member named 'InX' in 'X'
    1 | X::InX a; a
      | ~~~^
(lldb) expr b
(X::InX) $0 = 0
(lldb) expr -- X::InX a; a
(X::InX) $1 = 0

I don't know of any way to make this work other than to construct the typedefs eagerly.

Does anyone (@clayborg ?) know why the typedefs are constructed in this way? Is it because that would force us to also construct the type that the typedef refers to (and that was deemed too expensive)? If so, would #90663 help with that?

labath commented 1 week ago

On second though, let's create a separate issue (#91186) for that.