Watchpoint followed by catchpoint misreports watchpoint (PR gdb/28621)
authorPedro Alves <pedro@palves.net>
Tue, 23 Nov 2021 14:19:07 +0000 (14:19 +0000)
committerPedro Alves <pedro@palves.net>
Mon, 21 Mar 2022 17:27:17 +0000 (17:27 +0000)
commitd37e084783a04c63ae137f953ebdb58bb6f7f704
tree90e82c9060245f0cec3f94d3cb6a2a73bc8df4c0
parent4414150d33212f5f395c3bf8a940bccf80ffc508
Watchpoint followed by catchpoint misreports watchpoint (PR gdb/28621)

If GDB reports a watchpoint hit, and then the next event is not
TARGET_WAITKIND_STOPPED, but instead some event for which there's a
catchpoint, such that GDB calls bpstat_stop_status, GDB mistakenly
thinks the watchpoint triggered.  Vis, using foll-fork.c:

  (gdb) awatch v
  Hardware access (read/write) watchpoint 2: v
  (gdb) catch fork
  Catchpoint 3 (fork)
  (gdb) c
  Continuing.

  Hardware access (read/write) watchpoint 2: v

  Old value = 0
  New value = 5
  main () at gdb.base/foll-fork.c:16
  16        pid = fork ();
  (gdb)
  Continuing.

  Hardware access (read/write) watchpoint 2: v      <<<<
                                                    <<<< these lines are spurious
  Value = 5                                         <<<<

  Catchpoint 3 (forked process 1712369), arch_fork (ctid=0x7ffff7fa4810) at arch-fork.h:49
  49      arch-fork.h: No such file or directory.
  (gdb)

The problem is that when we handle the fork event, nothing called
watchpoints_triggered before calling bpstat_stop_status.  Thus, each
watchpoint's watchpoint_triggered field was still set to
watch_triggered_yes from the previous (real) watchpoint stop.
watchpoint_triggered is only current called in the handle_signal_stop
path, when handling TARGET_WAITKIND_STOPPED.

This fixes it by adding watchpoint_triggered calls in the other events
paths that call bpstat_stop_status.  But instead of adding them
explicitly, it adds a new function bpstat_stop_status_nowatch that
wraps bpstat_stop_status and calls watchpoint_triggered, and then
replaces most calls to bpstat_stop_status with calls to
bpstat_stop_status_nowatch.

This required constifying watchpoints_triggered.

New test included, which fails without the fix.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28621

Change-Id: I282b38c2eee428d25319af3bc842f9feafed461c
gdb/breakpoint.c
gdb/breakpoint.h
gdb/infrun.c
gdb/testsuite/gdb.base/watch-before-fork.c [new file with mode: 0644]
gdb/testsuite/gdb.base/watch-before-fork.exp [new file with mode: 0644]