llvm / llvm-project

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

LLDB reports empty `std::vector` when reproducer is compiled with `-D_GLIBCXX_DEBUG` #60841

Open tbaederr opened 1 year ago

tbaederr commented 1 year ago

Using this code:

#include <cassert>
#include <vector>

int main() {
  std::vector<int> V;
  V.push_back(12);
  assert(false);
  return 0;
}

shows the correct vector size in lldb when compiled with clang++ ./vec.cpp -g -std=c++20:

~ » lldb ./a.out -o run -o ' up 5' -o 'p V' -o q
(lldb) target create "./a.out"
Current executable set to '/home/tbaeder/a.out' (x86_64).
(lldb) run
a.out: ./vec.cpp:7: int main(): Assertion `false' failed.
Process 1492018 stopped
* thread #1, name = 'a.out', stop reason = signal SIGABRT
    frame #0: 0x00007ffff788ebec libc.so.6`__pthread_kill_implementation + 284
libc.so.6`__pthread_kill_implementation:
->  0x7ffff788ebec <+284>: movl   %eax, %ebp
    0x7ffff788ebee <+286>: negl   %ebp
    0x7ffff788ebf0 <+288>: cmpl   $0xfffff000, %eax         ; imm = 0xFFFFF000
    0x7ffff788ebf5 <+293>: movl   $0x0, %eax
Process 1492018 launched: '/home/tbaeder/a.out' (x86_64)
(lldb)  up 5
frame #5: 0x000000000040122d a.out`main at vec.cpp:7:3
   4    int main() {
   5      std::vector<int> V;
   6      V.push_back(12);
-> 7      assert(false);
   8      return 0;
   9    }
(lldb) p V
(std::vector<int, std::allocator<int> >) $0 = size=1 {
  [0] = 12
}
(lldb) q

But when compiled with clang++ ./vec.cpp -g -std=c++20 -D_GLIBCXX_DEBUG:

~ » lldb ./a.out -o run -o ' up 5' -o 'p V' -o q
(lldb) target create "./a.out"
Current executable set to '/home/tbaeder/a.out' (x86_64).
(lldb) run
a.out: ./vec.cpp:7: int main(): Assertion `false' failed.
Process 1492120 stopped
* thread #1, name = 'a.out', stop reason = signal SIGABRT
    frame #0: 0x00007ffff788ebec libc.so.6`__pthread_kill_implementation + 284
libc.so.6`__pthread_kill_implementation:
->  0x7ffff788ebec <+284>: movl   %eax, %ebp
    0x7ffff788ebee <+286>: negl   %ebp
    0x7ffff788ebf0 <+288>: cmpl   $0xfffff000, %eax         ; imm = 0xFFFFF000
    0x7ffff788ebf5 <+293>: movl   $0x0, %eax
Process 1492120 launched: '/home/tbaeder/a.out' (x86_64)
(lldb)  up 5
frame #5: 0x00000000004012bd a.out`main at vec.cpp:7:3
   4    int main() {
   5      std::vector<int> V;
   6      V.push_back(12);
-> 7      assert(false);
   8      return 0;
   9    }
(lldb) p V
(std::vector<int, std::allocator<int> >) $0 = size=0 {}
(lldb) q

... the size is reported as 0, which is clearly wrong.

Using lldb 15.0.7.

llvmbot commented 1 year ago

@llvm/issue-subscribers-lldb

Michael137 commented 1 year ago

That's most likely because the _GLIBCXX_DEBUG changes the layout of the vector, which the data formatter doesn't account for.

On my Ubuntu machine With the flag the raw layout is:

(lldb) frame var --raw v
(std::__debug::vector<int, std::allocator<int> >) v = {
  __gnu_debug::_Safe_container<std::__debug::vector<int, std::allocator<int> >, std::allocator<int>, __gnu_debug::_Safe_sequence, true> = {
    __gnu_debug::_Safe_sequence<std::__debug::vector<int, std::allocator<int> > > = {
      __gnu_debug::_Safe_sequence_base = {
        _M_iterators = nullptr
        _M_const_iterators = nullptr
        _M_version = 2
      }
    }
  }
  std::__cxx1998::vector<int, std::allocator<int> > = {
    std::__cxx1998::_Vector_base<int, std::allocator<int> > = {
      _M_impl = {
        std::__cxx1998::_Vector_base<int, std::allocator<int> >::_Vector_impl_data = {
          _M_start = 0x000055555556ceb0
          _M_finish = 0x000055555556ceb4
          _M_end_of_storage = 0x000055555556ceb4
        }
      }
    }
  }
  __gnu_debug::_Safe_vector<std::__debug::vector<int, std::allocator<int> >, std::__cxx1998::vector<int, std::allocator<int> > > = {
    _M_guaranteed_capacity = 1
  }
}

(lldb) type summary info v
summary applied to (std::vector<int, std::allocator<int> >) v is:  (show children) (hide value) libc++ std::vector summary provider

(lldb) type synthetic info v
synthetic applied to (std::vector<int, std::allocator<int> >) v is:  libc++ std::vector synthetic children

Looks like the summary provider that gets used for std::__debug::vector is the one for libc++.

Whereas the regular vector looks like:

(lldb) frame var --raw v
(std::vector<int, std::allocator<int> >) v = {
  std::_Vector_base<int, std::allocator<int> > = {
    _M_impl = {
      std::_Vector_base<int, std::allocator<int> >::_Vector_impl_data = {
        _M_start = 0x000055555556aeb0
        _M_finish = 0x000055555556aeb4
        _M_end_of_storage = 0x000055555556aeb4
      }
    }
  }
}

(lldb) type summary info v
summary applied to (std::vector<int, std::allocator<int> >) v is: `size=${svar%#}` (show children) (hide value)

(lldb) type synthetic info v
synthetic applied to (std::vector<int, std::allocator<int> >) v is:  Python class lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider

I think to fix this we'd have to adjust the std::vector formatter regex to account for the __debug namespace and then implement support for this layout in StdVectorSynthProvider (which lives in gnu_libstdcpp.py).