diff options
author | Bruno Larsen <blarsen@redhat.com> | 2022-02-22 11:44:44 -0300 |
---|---|---|
committer | Bruno Larsen <blarsen@redhat.com> | 2022-03-21 09:08:55 -0300 |
commit | daaf7acf47a12d10459060dca5500b63273cd683 (patch) | |
tree | 2588c3b660987ba49b11cc62674594ab73b0a81b /gdb/testsuite/gdb.python/pretty-print-call-by-hand.exp | |
parent | 9170b70c41064a0ba197dc7e2d6ecb940d2272bb (diff) | |
download | binutils-gdb-daaf7acf47a12d10459060dca5500b63273cd683.tar.gz |
[gdb/testsuite] test a function call by hand from pretty printer
The test case added here is testing the bug gdb/28856, where calling a
function by hand from a pretty printer makes GDB crash. There are 6
mechanisms to trigger this crash in the current test, using the commands
backtrace, up, down, finish, step and continue. Since the failure happens
because of use-after-free (more details below) the tests will always
have a chance of passing through sheer luck, but anecdotally they seem
to fail all of the time.
The reason GDB is crashing is a use-after-free problem. The above
mentioned functions save a pointer to the current frame's information,
then calls the pretty printer, and uses the saved pointer for different
reasons, depending on the function. The issue happens because
call_function_by_hand needs to reset the obstack to get the current
frame, invalidating the saved pointer.
Diffstat (limited to 'gdb/testsuite/gdb.python/pretty-print-call-by-hand.exp')
-rw-r--r-- | gdb/testsuite/gdb.python/pretty-print-call-by-hand.exp | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.python/pretty-print-call-by-hand.exp b/gdb/testsuite/gdb.python/pretty-print-call-by-hand.exp new file mode 100644 index 00000000000..0a6d014cf12 --- /dev/null +++ b/gdb/testsuite/gdb.python/pretty-print-call-by-hand.exp @@ -0,0 +1,127 @@ +# Copyright (C) 2022 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# This file is part of the GDB testsuite. It tests a pretty printer that +# calls an inferior function by hand, triggering a Use-after-Free bug +# (PR gdb/28856). + +load_lib gdb-python.exp + +standard_testfile + +# gdb needs to be started here for skip_python_tests to work. +# prepare_for_testing could be used instead, but it could compile the program +# unnecessarily, so starting GDB like this is preferable. +gdb_start + +# Skip all tests if Python scripting is not enabled. +if { [skip_python_tests] } { continue } + +if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } { + untested "failed to compile" + return -1 +} + +# This proc restarts GDB, makes the inferior reach the desired spot - marked +# by a comment in the .c file - and turns on the pretty printer for testing. +# Starting with a new GDB is important because the test may crash GDB. The +# return values are here to avoid us trying to test the pretty printer if +# there was a problem getting to main. +proc start_test { breakpoint_comment } { + global srcdir subdir testfile binfile + + # Start with a fresh gdb. + # This is important because the test can crash GDB. + + clean_restart ${binfile} + + if { ![runto_main] } then { + untested "couldn't run to breakpoint" + return -1 + } + + # Let GDB get to the return line. + gdb_breakpoint [gdb_get_line_number ${breakpoint_comment} ${testfile}.c ] + gdb_continue_to_breakpoint ${breakpoint_comment} ".*" + + gdb_test_no_output "set print pretty on" "starting to pretty print" + + set remote_python_file [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] + gdb_test_no_output "source ${remote_python_file}" "load python file" + + return 0 +} + +# Testing the backtrace command. +with_test_prefix "frame print" { + if { [start_test "TAG: final frame"] == 0 } { + setup_kfail gdb/28856 "*-*-*" + gdb_test "backtrace -frame-arguments all" [multi_line \ + "#0 .*g \\(mt=mytype is .*\\).*"\ + "#1 .*g \\(mt=mytype is .*\\).*"\ + "#2 .*g \\(mt=mytype is .*\\).*"\ + "#3 .*g \\(mt=mytype is .*\\).*"\ + "#4 .*g \\(mt=mytype is .*\\).*"\ + "#5 .*g \\(mt=mytype is .*\\).*"\ + "#6 .*g \\(mt=mytype is .*\\).*"\ + "#7 .*g \\(mt=mytype is .*\\).*"\ + "#8 .*g \\(mt=mytype is .*\\).*"\ + "#9 .*g \\(mt=mytype is .*\\).*"\ + "#10 .*g \\(mt=mytype is .*\\).*"\ + "#11 .*main \\(\\).*"] \ + "backtrace test" + } +} +# Testing the down command. +with_test_prefix "frame movement down" { + if { [start_test "TAG: first frame"] == 0 } { + gdb_test "up" [multi_line "#1 .*in main \\(\\) at .*" ".*outside the frame.*"] + setup_kfail gdb/28856 "*-*-*" + gdb_test "down" [multi_line "#0\\s+g \\(mt=mytype is .*\\).*" ".*first frame.*"] + } +} + +# Testing the up command. +with_test_prefix "frame movement up" { + if { [start_test "TAG: final frame"] == 0 } { + setup_kfail gdb/28856 "*-*-*" + gdb_test "up" [multi_line "#1 .*in g \\(mt=mytype is .*\\).*" ".*first frame.*"] + } +} + +# Testing the finish command. +with_test_prefix "frame exit through finish" { + if { [start_test "TAG: final frame"] == 0 } { + setup_kfail gdb/28856 "*-*-*" + gdb_test "finish" [multi_line "Run till exit from #0 .*" ".* g \\(mt=mytype is .*\\, depth=1\\).*" ".*first frame.*"] + } +} + +# Testing the step command. +with_test_prefix "frame enter through step" { + if { [start_test "TAG: outside the frame"] == 0 } { + setup_kfail gdb/28856 "*-*-*" + gdb_test "step" [multi_line "g \\(mt=mytype is .*\\, depth=10\\).*" "41.*if \\(depth \\<= 0\\)"] + } +} + +# Testing the continue command. +with_test_prefix "frame enter through continue" { + if { [start_test "TAG: outside the frame"] == 0 } { + setup_kfail gdb/28856 "*-*-*" + gdb_breakpoint [gdb_get_line_number "TAG: first frame" ${testfile}.c ] + gdb_continue_to_breakpoint "TAG: first frame" ".*TAG: first frame.*" + } +} |