Skip to content

Commit 801a576

Browse files
authored
Handle xdebug conflict on dump_on_limit feature (#68)
1 parent a23ec74 commit 801a576

File tree

5 files changed

+111
-3
lines changed

5 files changed

+111
-3
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ jobs:
5656
- name: 'Build PHP'
5757
run: './ext/.github/workflows/test/build-php.sh'
5858

59+
- name: 'Install xdebug'
60+
run: './ext/.github/workflows/test/build-xdebug.sh'
61+
5962
- name: 'Build extension'
6063
run: './ext/.github/workflows/test/build-extension.sh'
6164

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/sh
2+
3+
set -e
4+
5+
export PATH="$HOME/php/bin:$PATH"
6+
hash -r
7+
8+
git clone --depth 1 --branch "3.1.2" "https://github.com/xdebug/xdebug.git"
9+
10+
cd xdebug
11+
12+
phpize
13+
./configure
14+
make
15+
sudo make install

.github/workflows/test/tests.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,9 @@ if [ "$MEMORY_CHECK" = "1" ]; then
1313
checkmem=-m
1414
fi
1515

16+
# Hack to ensure that run-tests.php attempts to load xdebug as a zend_extension
17+
# This hack is necessary with PHP < 8.1
18+
sed -i "s/if (\$req_ext == 'opcache') {/if (\$req_ext == 'opcache' || \$req_ext == 'xdebug') {/" run-tests.php || true
19+
1620
PHP=$(which php)
1721
REPORT_EXIT_STATUS=1 TEST_PHP_EXECUTABLE="$PHP" "$PHP" run-tests.php -q $checkmem --show-diff $showmem

memprof.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@ static void (*old_zend_execute_internal)(zend_execute_data *execute_data_ptr, zv
217217
#endif
218218

219219
static void (*old_zend_error_cb)(MEMPROF_ZEND_ERROR_CB_ARGS);
220+
static void (*rinit_zend_error_cb)(MEMPROF_ZEND_ERROR_CB_ARGS);
221+
static zend_bool zend_error_cb_overridden;
222+
static void memprof_zend_error_cb(MEMPROF_ZEND_ERROR_CB_ARGS);
220223

221224
static PHP_INI_MH((*origOnChangeMemoryLimit)) = NULL;
222225

@@ -718,8 +721,20 @@ static void * zend_realloc_handler(void * ptr, size_t size)
718721
return result;
719722
}
720723

724+
// Some extensions override zend_error_cb and don't call the previous
725+
// zend_error_cb, so memprof needs to be the last to override it
726+
static void memprof_late_override_error_cb() {
727+
old_zend_error_cb = zend_error_cb;
728+
zend_error_cb = memprof_zend_error_cb;
729+
zend_error_cb_overridden = 1;
730+
}
731+
721732
static void memprof_zend_execute(zend_execute_data *execute_data)
722733
{
734+
if (UNEXPECTED(!zend_error_cb_overridden)) {
735+
memprof_late_override_error_cb();
736+
}
737+
723738
WITHOUT_MALLOC_TRACKING {
724739

725740
current_frame = get_or_create_frame(execute_data, current_frame);
@@ -740,6 +755,10 @@ static void memprof_zend_execute_internal(zend_execute_data *execute_data_ptr, z
740755
{
741756
int ignore = 0;
742757

758+
if (UNEXPECTED(!zend_error_cb_overridden)) {
759+
memprof_late_override_error_cb();
760+
}
761+
743762
if (&execute_data_ptr->func->internal_function == &zend_pass_function) {
744763
ignore = 1;
745764
} else if (execute_data_ptr->func->common.function_name) {
@@ -1191,9 +1210,6 @@ PHP_MINIT_FUNCTION(memprof)
11911210
}
11921211
}
11931212

1194-
old_zend_error_cb = zend_error_cb;
1195-
zend_error_cb = memprof_zend_error_cb;
1196-
11971213
return SUCCESS;
11981214
}
11991215
/* }}} */
@@ -1231,6 +1247,9 @@ PHP_RINIT_FUNCTION(memprof)
12311247
memprof_enable(&MEMPROF_G(profile_flags));
12321248
}
12331249

1250+
rinit_zend_error_cb = zend_error_cb;
1251+
zend_error_cb_overridden = 0;
1252+
12341253
return SUCCESS;
12351254
}
12361255
/* }}} */
@@ -1243,6 +1262,8 @@ PHP_RSHUTDOWN_FUNCTION(memprof)
12431262
memprof_disable();
12441263
}
12451264

1265+
zend_error_cb = rinit_zend_error_cb;
1266+
12461267
return SUCCESS;
12471268
}
12481269
/* }}} */

tests/autodump-xdebug.phpt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
autodump vs xdebug
3+
--EXTENSIONS--
4+
xdebug
5+
--INI--
6+
xdebug.mode=develop
7+
--ENV--
8+
MEMPROF_PROFILE=dump_on_limit
9+
--FILE--
10+
<?php
11+
12+
$dir = sys_get_temp_dir() . '/' . microtime(true);
13+
var_dump($dir);
14+
var_dump(mkdir($dir));
15+
var_dump(memprof_enabled_flags());
16+
17+
$buf = str_repeat("a", 5<<20);
18+
19+
register_shutdown_function(function () use (&$buf, $dir) {
20+
$buf = "";
21+
var_dump(scandir($dir));
22+
});
23+
24+
ini_set("memprof.output_dir", $dir);
25+
ini_set("memory_limit", 15<<20);
26+
27+
function f() {
28+
$a = [];
29+
for (;;) {
30+
$a[] = str_repeat("a", 1<<20);
31+
}
32+
}
33+
34+
f();
35+
--EXPECTF--
36+
%sautodump-xdebug.php:%d:
37+
string(%d) "/%s"
38+
%sautodump-xdebug.php:%d:
39+
bool(true)
40+
%sautodump-xdebug.php:%d:
41+
array(3) {
42+
'enabled' =>
43+
bool(true)
44+
'native' =>
45+
bool(false)
46+
'dump_on_limit' =>
47+
bool(true)
48+
}
49+
50+
Fatal error: Allowed memory size of 15728640 bytes exhausted%S (tried to allocate %d bytes) (memprof dumped to %smemprof.callgrind%s) in %s on line%a
51+
52+
Call Stack:
53+
%s
54+
%s
55+
%s
56+
57+
%sautodump-xdebug.php:%d:
58+
array(3) {
59+
[0] =>
60+
string(1) "."
61+
[1] =>
62+
string(2) ".."
63+
[2] =>
64+
string(%d) "memprof.callgrind.%s"
65+
}

0 commit comments

Comments
 (0)