Skip to content

Commit b39ff33

Browse files
committed
Merge branch 'PHP-8.2'
* PHP-8.2: Re-add some CTE functions that were removed from being CTE by a mistake Fix GH-8065: opcache.consistency_checks > 0 causes segfaults in PHP >= 8.1.5 in fpm context Fix GH-8646: Memory leak PHP FPM 8.1
2 parents 3821938 + 411cd04 commit b39ff33

File tree

11 files changed

+151
-12
lines changed

11 files changed

+151
-12
lines changed

Zend/zend.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,34 @@ ZEND_API void zend_deactivate(void) /* {{{ */
12811281

12821282
zend_destroy_rsrc_list(&EG(regular_list));
12831283

1284+
/* See GH-8646: https://github.com/php/php-src/issues/8646
1285+
*
1286+
* Interned strings that hold class entries can get a corresponding slot in map_ptr for the CE cache.
1287+
* map_ptr works like a bump allocator: there is a counter which increases to allocate the next slot in the map.
1288+
*
1289+
* For class name strings in non-opcache we have:
1290+
* - on startup: permanent + interned
1291+
* - on request: interned
1292+
* For class name strings in opcache we have:
1293+
* - on startup: permanent + interned
1294+
* - on request: either not interned at all, which we can ignore because they won't get a CE cache entry
1295+
* or they were already permanent + interned
1296+
* or we get a new permanent + interned string in the opcache persistence code
1297+
*
1298+
* Notice that the map_ptr layout always has the permanent strings first, and the request strings after.
1299+
* In non-opcache, a request string may get a slot in map_ptr, and that interned request string
1300+
* gets destroyed at the end of the request. The corresponding map_ptr slot can thereafter never be used again.
1301+
* This causes map_ptr to keep reallocating to larger and larger sizes.
1302+
*
1303+
* We solve it as follows:
1304+
* We can check whether we had any interned request strings, which only happens in non-opcache.
1305+
* If we have any, we reset map_ptr to the last permanent string.
1306+
* We can't lose any permanent strings because of map_ptr's layout.
1307+
*/
1308+
if (zend_hash_num_elements(&CG(interned_strings)) > 0) {
1309+
zend_map_ptr_reset();
1310+
}
1311+
12841312
#if GC_BENCH
12851313
fprintf(stderr, "GC Statistics\n");
12861314
fprintf(stderr, "-------------\n");

ext/gd/gd.stub.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@ function imagesetbrush(GdImage $image, GdImage $brush): bool {}
541541
/** @refcount 1 */
542542
function imagecreate(int $width, int $height): GdImage|false {}
543543

544+
/** @compile-time-eval */
544545
function imagetypes(): int {}
545546

546547
/** @refcount 1 */

ext/gd/gd_arginfo.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/opcache/tests/gh8065.phpt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
GH-8065: opcache.consistency_checks > 0 causes segfaults in PHP >= 8.1.5 in fpm context
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.enable_cli=1
7+
opcache.consistency_checks=1
8+
opcache.log_verbosity_level=2
9+
--FILE--
10+
<?php
11+
var_dump(ini_get("opcache.consistency_checks"));
12+
var_dump(ini_set("opcache.consistency_checks", 1));
13+
var_dump(ini_set("opcache.consistency_checks", -1));
14+
var_dump(ini_set("opcache.consistency_checks", 0));
15+
?>
16+
--EXPECTF--
17+
%sWarning opcache.consistency_checks is reset back to 0 because it does not work properly (see GH-8065, GH-10624).
18+
19+
string(1) "0"
20+
%sWarning opcache.consistency_checks is reset back to 0 because it does not work properly (see GH-8065, GH-10624).
21+
22+
bool(false)
23+
%sWarning opcache.consistency_checks is reset back to 0 because it does not work properly (see GH-8065, GH-10624).
24+
25+
bool(false)
26+
string(1) "0"

ext/opcache/zend_accelerator_module.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,19 @@ static ZEND_INI_MH(OnUpdateMaxWastedPercentage)
129129
return SUCCESS;
130130
}
131131

132+
static ZEND_INI_MH(OnUpdateConsistencyChecks)
133+
{
134+
zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
135+
zend_long consistency_checks = atoi(ZSTR_VAL(new_value));
136+
137+
if (consistency_checks != 0) {
138+
zend_accel_error(ACCEL_LOG_WARNING, "opcache.consistency_checks is reset back to 0 because it does not work properly (see GH-8065, GH-10624).\n");
139+
return FAILURE;
140+
}
141+
*p = 0;
142+
return SUCCESS;
143+
}
144+
132145
static ZEND_INI_MH(OnEnable)
133146
{
134147
if (stage == ZEND_INI_STAGE_STARTUP ||
@@ -263,7 +276,7 @@ ZEND_INI_BEGIN()
263276
STD_PHP_INI_ENTRY("opcache.interned_strings_buffer", "8" , PHP_INI_SYSTEM, OnUpdateInternedStringsBuffer, accel_directives.interned_strings_buffer, zend_accel_globals, accel_globals)
264277
STD_PHP_INI_ENTRY("opcache.max_accelerated_files" , "10000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles, accel_directives.max_accelerated_files, zend_accel_globals, accel_globals)
265278
STD_PHP_INI_ENTRY("opcache.max_wasted_percentage" , "5" , PHP_INI_SYSTEM, OnUpdateMaxWastedPercentage, accel_directives.max_wasted_percentage, zend_accel_globals, accel_globals)
266-
STD_PHP_INI_ENTRY("opcache.consistency_checks" , "0" , PHP_INI_ALL , OnUpdateLong, accel_directives.consistency_checks, zend_accel_globals, accel_globals)
279+
STD_PHP_INI_ENTRY("opcache.consistency_checks" , "0" , PHP_INI_ALL , OnUpdateConsistencyChecks, accel_directives.consistency_checks, zend_accel_globals, accel_globals)
267280
STD_PHP_INI_ENTRY("opcache.force_restart_timeout" , "180" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.force_restart_timeout, zend_accel_globals, accel_globals)
268281
STD_PHP_INI_ENTRY("opcache.revalidate_freq" , "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.revalidate_freq, zend_accel_globals, accel_globals)
269282
STD_PHP_INI_ENTRY("opcache.file_update_protection", "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.file_update_protection, zend_accel_globals, accel_globals)

ext/standard/basic_functions.stub.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,7 +1846,10 @@ function array_filter(array $array, ?callable $callback = null, int $mode = 0):
18461846

18471847
function array_map(?callable $callback, array $array, array ...$arrays): array {}
18481848

1849-
/** @param string|int $key */
1849+
/**
1850+
* @param string|int $key
1851+
* @compile-time-eval
1852+
*/
18501853
function array_key_exists($key, array $array): bool {}
18511854

18521855
/**
@@ -1859,6 +1862,7 @@ function array_chunk(array $array, int $length, bool $preserve_keys = false): ar
18591862

18601863
function array_combine(array $keys, array $values): array {}
18611864

1865+
/** @compile-time-eval */
18621866
function array_is_list(array $array): bool {}
18631867

18641868
/* base64.c */
@@ -2314,7 +2318,10 @@ function pathinfo(string $path, int $flags = PATHINFO_ALL): array|string {}
23142318
/** @refcount 1 */
23152319
function stristr(string $haystack, string $needle, bool $before_needle = false): string|false {}
23162320

2317-
/** @refcount 1 */
2321+
/**
2322+
* @compile-time-eval
2323+
* @refcount 1
2324+
*/
23182325
function strstr(string $haystack, string $needle, bool $before_needle = false): string|false {}
23192326

23202327
/** @alias strstr */

ext/standard/basic_functions_arginfo.h

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/zend_test/test.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,12 @@ static ZEND_FUNCTION(zend_test_zend_call_stack_use_all)
527527
}
528528
#endif /* ZEND_CHECK_STACK_LIMIT */
529529

530+
static ZEND_FUNCTION(zend_get_map_ptr_last)
531+
{
532+
ZEND_PARSE_PARAMETERS_NONE();
533+
RETURN_LONG(CG(map_ptr_last));
534+
}
535+
530536
static zend_object *zend_test_class_new(zend_class_entry *class_type)
531537
{
532538
zend_object *obj = zend_objects_new(class_type);

ext/zend_test/test.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ function zend_test_zend_call_stack_use_all(): int {}
188188
#endif
189189

190190
function zend_test_is_string_marked_as_valid_utf8(string $string): bool {}
191+
192+
function zend_get_map_ptr_last(): int {}
191193
}
192194

193195
namespace ZendTestNS {

ext/zend_test/test_arginfo.h

Lines changed: 7 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sapi/fpm/tests/gh8646.phpt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
--TEST--
2+
GH-8646 (Memory leak PHP FPM 8.1)
3+
--EXTENSIONS--
4+
zend_test
5+
--SKIPIF--
6+
<?php include "skipif.inc"; ?>
7+
--FILE--
8+
<?php
9+
10+
require_once "tester.inc";
11+
12+
$cfg = <<<EOT
13+
[global]
14+
error_log = {{FILE:LOG}}
15+
[unconfined]
16+
listen = {{ADDR}}
17+
pm = dynamic
18+
pm.max_children = 5
19+
pm.start_servers = 1
20+
pm.min_spare_servers = 1
21+
pm.max_spare_servers = 3
22+
EOT;
23+
24+
$code = <<<EOT
25+
<?php
26+
class MyClass {}
27+
echo zend_get_map_ptr_last();
28+
EOT;
29+
30+
$tester = new FPM\Tester($cfg, $code);
31+
$tester->start();
32+
$tester->expectLogStartNotices();
33+
$map_ptr_last_values = [];
34+
for ($i = 0; $i < 10; $i++) {
35+
$map_ptr_last_values[] = (int) $tester->request()->getBody();
36+
}
37+
// Ensure that map_ptr_last did not increase
38+
var_dump(count(array_unique($map_ptr_last_values, SORT_REGULAR)) === 1);
39+
$tester->terminate();
40+
$tester->expectLogTerminatingNotices();
41+
$tester->close();
42+
43+
?>
44+
Done
45+
--EXPECT--
46+
bool(true)
47+
Done
48+
--CLEAN--
49+
<?php
50+
require_once "tester.inc";
51+
FPM\Tester::clean();
52+
?>

0 commit comments

Comments
 (0)