mirror of
https://github.com/php/php-src.git
synced 2026-10-28 17:56:50 +08:00
phpdbg_add_watch_element() frees the passed element and returns the existing one when the variable is already watched, but several callers kept using the freed pointer, so re-watching a variable was a use-after-free in more places than the two reported. Report the duplicate back through the parse callback and register nothing, and reject a recursive watch's hashtable element that collides with an existing watch, at creation and recreation, rather than freeing a still-referenced one. A recursive watch over an already-array-watched variable now watches only the root and skips the shared hashtable. Running the tests under ASAN exposed a second, latent use-after-free at shutdown: the watch tables are module-scoped but hold request-pool memory, so under the tracked allocator freeing a watched variable during executor teardown re-queues an element after the last drain, tracked_free_all frees the pool, and phpdbg_destroy_watchpoints reads it at module shutdown. Tear the watch state down in a post_deactivate handler, which runs after the executor frees values but before the memory manager is torn down. Dropping watch_006's xfail surfaced a separate pre-existing bug on large-page platforms: the fault handler rechecks every watchpoint on the faulting page, so on 16 KB pages a value-only write to an element can fault the page holding a watched hashtable's own struct and run the recursive rescan, which re-reported existing elements as freshly added. Only run that rescan when the element count actually changed. Fixes GH-22480
35 lines
615 B
PHP
35 lines
615 B
PHP
--TEST--
|
|
GH-22480 (Use-after-free when re-watching an already-watched variable)
|
|
--PHPDBG--
|
|
b 6
|
|
r
|
|
w a $a
|
|
w a $a
|
|
c
|
|
|
|
q
|
|
--EXPECTF--
|
|
[Successful compilation of %s]
|
|
prompt> [Breakpoint #0 added at %s:6]
|
|
prompt> [Breakpoint #0 at %s:6, hits: 1]
|
|
>00006: $a[0] = 2;
|
|
00007:
|
|
00008: $a = [0 => 3, 1 => 4];
|
|
prompt> [Added watchpoint #0 for $a[]]
|
|
prompt> [$a[] is already being watched]
|
|
prompt> [Breaking on watchpoint $a[]]
|
|
1 elements were added to the array
|
|
>00009:
|
|
prompt> [$a[] has been removed, removing watchpoint]
|
|
[Script ended normally]
|
|
prompt>
|
|
--FILE--
|
|
<?php
|
|
|
|
$a = [];
|
|
|
|
$a[0] = 1;
|
|
$a[0] = 2;
|
|
|
|
$a = [0 => 3, 1 => 4];
|