Skip to content

Commit 08e8a8f

Browse files
committed
Fix GH-15210: phpdbg_print_changed_zvals working on a real copy instead.
1 parent 67ce875 commit 08e8a8f

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

sapi/phpdbg/phpdbg_watch.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,8 +1168,9 @@ int phpdbg_print_changed_zvals(void) {
11681168

11691169
if (zend_hash_num_elements(PHPDBG_G(watchlist_mem)) > 0) {
11701170
/* we must not add elements to the hashtable while iterating over it (resize => read into freed memory) */
1171-
mem_list = PHPDBG_G(watchlist_mem);
1172-
PHPDBG_G(watchlist_mem) = PHPDBG_G(watchlist_mem_backup);
1171+
mem_list = malloc(phpdbg_pagesize > sizeof(HashTable) ? phpdbg_pagesize : sizeof(HashTable));
1172+
zend_hash_init(mem_list, zend_hash_num_elements(PHPDBG_G(watchlist_mem)), NULL, NULL, false);
1173+
zend_hash_copy(mem_list, PHPDBG_G(watchlist_mem), (copy_ctor_func_t) zval_add_ref);
11731174

11741175
ZEND_HASH_MAP_FOREACH_NUM_KEY(mem_list, page) {
11751176
phpdbg_btree_position pos = phpdbg_btree_find_between(&PHPDBG_G(watchpoint_tree), page, page + phpdbg_pagesize);
@@ -1192,7 +1193,13 @@ int phpdbg_print_changed_zvals(void) {
11921193
phpdbg_reenable_memory_watches();
11931194

11941195
if (mem_list) {
1195-
PHPDBG_G(watchlist_mem) = mem_list;
1196+
zend_hash_destroy(PHPDBG_G(watchlist_mem));
1197+
free(PHPDBG_G(watchlist_mem));
1198+
PHPDBG_G(watchlist_mem) = malloc(phpdbg_pagesize > sizeof(HashTable) ? phpdbg_pagesize : sizeof(HashTable));
1199+
zend_hash_init(PHPDBG_G(watchlist_mem), phpdbg_pagesize / (sizeof(Bucket) + sizeof(uint32_t)), NULL, NULL, true);
1200+
zend_hash_copy(PHPDBG_G(watchlist_mem), mem_list, (copy_ctor_func_t) zval_add_ref);
1201+
zend_hash_destroy(mem_list);
1202+
free(mem_list);
11961203
phpdbg_reenable_memory_watches();
11971204
}
11981205

sapi/phpdbg/tests/gh15210.phpt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
GH-15210 use after free after continue
3+
--CREDITS--
4+
YuanchengJiang
5+
--PHPDBG--
6+
b 4
7+
r
8+
w $a[0]
9+
w r $b
10+
c
11+
q
12+
--FILE--
13+
<?php
14+
header_register_callback(function() { echo "sent";});
15+
$a = [0];
16+
$a[0] = 1;
17+
$b = &$a;
18+
$a[0] = 2;
19+
$a[1] = 3;
20+
$c = [1];
21+
$b = &$c;
22+
?>
23+
--EXPECTF--
24+
[Successful compilation of %s]
25+
prompt> [Breakpoint #0 added at %s:%d]
26+
prompt> [Breakpoint #0 at %s:%d, hits: 1]
27+
>00004: $a[0] = 1;
28+
00005: $b = &$a;
29+
00006: $a[0] = 2;
30+
prompt> [Added watchpoint #0 for $a[0]]
31+
prompt> [Added recursive watchpoint #1 for $b]
32+
prompt> [Breaking on watchpoint $a[0]]
33+
Old value: [Breaking on watchpoint $a[0]]
34+
Old value: 0
35+
New value: 1
36+
>00002: header_register_callback(function() { echo "sent";});
37+
00003: $a = [0];
38+
00004: $a[0] = 1;
39+
prompt> [$a[0] has been removed, removing watchpoint]
40+
[$b has been removed, removing watchpoint recursively]

0 commit comments

Comments
 (0)