]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commit
[gdb/c++] Fix hang on whatis std::string::npos
authorTom de Vries <tdevries@suse.de>
Thu, 16 Oct 2025 09:38:53 +0000 (11:38 +0200)
committerTom de Vries <tdevries@suse.de>
Thu, 16 Oct 2025 09:38:53 +0000 (11:38 +0200)
commitfb81c8c1a6d51ff98d035c0c44efe606033b7c64
tree947bb41260178d62bc1465548cffd4a4ea2fb5e6
parent5a7173cd46252fbbac5c7b30efebd2d66aad5eb3
[gdb/c++] Fix hang on whatis std::string::npos

Consider the following scenario, exercising "whatis std::string::npos":
...
$ cat test.cc
int main (void) {
  std::string foo = "bar";
  return foo.size ();
}
$ g++ test.cc -g
$ gdb -q -batch -iex "set trace-commands on" a.out -x gdb.in
+start
Temporary breakpoint 1 at 0x4021c7: file test.cc, line 3.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Temporary breakpoint 1, main () at test.cc:3
3   std::string foo = "bar";
+info auto-load python-scripts
No auto-load scripts.
+whatis std::string
type = std::__cxx11::basic_string<char, std::char_traits<char>, \
  std::allocator<char> >
+whatis std::string::npos
type = const std::__cxx11::basic_string<char, std::char_traits<char>, \
  std::allocator<char> >::size_type
...

After installing the package containing the pretty-printers:
...
$ zypper install libstdc++6-pp
...
and adding some commands to use them, we get instead:
...
$ gdb -q -batch -iex "set trace-commands on" a.out -x gdb.in
+add-auto-load-safe-path /usr/share/gdb/auto-load
+add-auto-load-scripts-directory /usr/share/gdb/auto-load
+start
  ...
+info auto-load python-scripts
Loaded  Script
Yes     /usr/share/gdb/auto-load/usr/lib64/libstdc++.so.6.0.34-gdb.py
+whatis std::string
type = std::string
+whatis std::string::npos
type = const std::__cxx11::basic_string<char, std::char_traits<char>, \
  std::allocator<char> >::size_type
...

Note that "whatis std::string" now prints "std::string", but that
"whatis std::string::npos" still uses the longer name for std::string.

This is when compiling gdb with -O0.  With -O2 -fstack-protector-strong, we
have a hang instead:
...
+whatis std::string
type = std::string
+whatis std::string::npos
<HANG>
...

Valgrind complains about an uninitialized field
demangle_component::d_counting, which is fixed by using
cplus_demangle_fill_name in replace_typedefs_qualified_name.

After fixing that, the hang is also reproducible at -O0.

The hang happens because we're stuck in the while loop in
replace_typedefs_qualified_name, replacing "std::string::size_type" with
"std::string::size_type".

Fix this in inspect_type by checking for this situation, getting us instead:
...
+whatis std::string
type = std::string
+whatis std::string::npos
type = const std::string::size_type
$
...

The test-case is a bit unusual:
- pretty-print.cc is a preprocessed c++ source, reduced using cvise [1], then
  hand-edited to fix warnings with gcc and clang.
- the pretty-printer .py file is a reduced version of
  /usr/share/gcc-15/python/libstdcxx/v6/printers.py.

Using the test-case (and the cplus_demangle_fill_name fix), I managed to
reproduce the hang on both:
- openSUSE Leap 15.6 with gcc 7, and
- openSUSE Tumbleweed with gcc 15.

The test-case compiles with clang, but the hang didn't reproduce.

Tested on x86_64-linux.

PR testsuite/33480
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33480

[1] https://github.com/marxin/cvise
gdb/cp-support.c
gdb/testsuite/gdb.cp/pretty-print.cc [new file with mode: 0644]
gdb/testsuite/gdb.cp/pretty-print.exp [new file with mode: 0644]
gdb/testsuite/gdb.cp/pretty-print.py [new file with mode: 0644]