[PATCH] Fix segfault when using 'set print object on' + whatis

Sergio Durigan Junior
2018-01-20T01:03:43Z

This problem was hidden behind a "maybe-uninitialized" warning
generated when compiling GDB with a recent GCC. The warning is:

../../gdb/typeprint.c: In function 'void whatis_exp(const char*, int)':
../../gdb/typeprint.c:515:12: warning: 'val' may be used uninitialized in this function [-Wmaybe-uninitialized]
real_type = value_rtti_type (val, &full, &top, &using_enc);
~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I submitted a patch fixing this by initializing "val" to NULL, but it
was the wrong fix, as Pedro pointed out on
<https://sourceware.org/ml/gdb-patches/2018-01/msg00346.html>:

(gdb) set print object on
(gdb) whatis some_structure_type

Thread 1 "gdb" received signal SIGSEGV, Segmentation fault.
0x00000000005dda90 in check_typedef (type=0x6120736573756170) at src/gdb/gdbtypes.c:2388
2388 int instance_flags = TYPE_INSTANCE_FLAGS (type);
...

So I set off to find the cause of the problem. It turns out that a
recent-ish refactoring of the code on 'whatis_exp', introduced by:

commit c973d0aa4a2c737ab527ae44a617f1c357e07364
Date: Mon Aug 21 11:34:32 2017 +0100

Fix type casts losing typedefs and reimplement "whatis" typedef stripping

was the reason of the failure. After investigating what 'set print
object on' was supposed to do to the output of 'whatis', if made sense
initialize "val = evaluate_type (expr.get ());" all the time, not only
when we're dealing with the 'ptype' command.

I've regtested this on the BuildBot, without seeing any regressions.
I've also extended 'gdb.base/whatis.exp' to check if the segfault is
not there anymore.

gdb/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <sergiodj@redhat.com>

* typeprint.c (whatis_exp): Move initialization of "val"
outside of "if".

gdb/testsuite/ChangeLog:
yyyy-mm-dd Sergio Durigan Junior <sergiodj@redhat.com>

* gdb.base/whatis.exp: Test that 'set print object on' +
'whatis <struct>' doesn't segfault.
---
gdb/testsuite/gdb.base/whatis.exp | 7 +++++++
gdb/typeprint.c | 3 ++-
2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/gdb/testsuite/gdb.base/whatis.exp b/gdb/testsuite/gdb.base/whatis.exp
index dd6aeb02f9..8207dab59c 100644
--- a/gdb/testsuite/gdb.base/whatis.exp
+++ b/gdb/testsuite/gdb.base/whatis.exp
@@ -566,3 +566,10 @@ gdb_test "whatis int (*)(void, int, int)" \
gdb_test "whatis int (*)(int, void, int)" \
"'void' invalid as parameter type" \
"whatis applied to function with 'void' parameter type"
+
+# Test that 'set print object on' + whatis doesn't segfault.
+clean_restart $binfile
+gdb_test_no_output "set print object on"
+gdb_test "whatis v_struct1" \
+ "type = struct t_struct" \
+ "whatis + set print object on doesn't segfault"
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 9a125076a1..dd6e75bd4f 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -471,6 +471,8 @@ whatis_exp (const char *exp, int show)

expression_up expr = parse_expression (exp);

+ val = evaluate_type (expr.get ());
+
/* The behavior of "whatis" depends on whether the user
expression names a type directly, or a language expression
(including variable names). If the former, then "whatis"
@@ -495,7 +497,6 @@ whatis_exp (const char *exp, int show)
/* The user expression names a type indirectly by naming an
object or expression of that type. Find that
indirectly-named type. */
- val = evaluate_type (expr.get ());
type = value_type (val);
}
}
--
2.14.3