Skip to content

Commit d50393e

Browse files
committed
Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2: Fix GH-12504: Corrupted session written when there's a fatal error in autoloader
2 parents 0becd48 + 7f7031e commit d50393e

File tree

3 files changed

+82
-6
lines changed

3 files changed

+82
-6
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ PHP NEWS
4444
. Fixed bug GH-13138 (Randomizer::pickArrayKeys() does not detect broken
4545
engines). (timwolla)
4646

47+
- Session:
48+
. Fixed bug GH-12504 (Corrupted session written when there's a fatal error
49+
in autoloader). (nielsdos)
50+
4751
- Standard:
4852
. Fixed bug GH-13094 (range(9.9, '0') causes segmentation fault). (nielsdos)
4953

ext/session/session.c

+16-6
Original file line numberDiff line numberDiff line change
@@ -258,18 +258,28 @@ static zend_string *php_session_encode(void) /* {{{ */
258258
}
259259
/* }}} */
260260

261+
static ZEND_COLD void php_session_cancel_decode(void)
262+
{
263+
php_session_destroy();
264+
php_session_track_init();
265+
php_error_docref(NULL, E_WARNING, "Failed to decode session object. Session has been destroyed");
266+
}
267+
261268
static zend_result php_session_decode(zend_string *data) /* {{{ */
262269
{
263270
if (!PS(serializer)) {
264271
php_error_docref(NULL, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object");
265272
return FAILURE;
266273
}
267-
if (PS(serializer)->decode(ZSTR_VAL(data), ZSTR_LEN(data)) == FAILURE) {
268-
php_session_destroy();
269-
php_session_track_init();
270-
php_error_docref(NULL, E_WARNING, "Failed to decode session object. Session has been destroyed");
271-
return FAILURE;
272-
}
274+
zend_try {
275+
if (PS(serializer)->decode(ZSTR_VAL(data), ZSTR_LEN(data)) == FAILURE) {
276+
php_session_cancel_decode();
277+
return FAILURE;
278+
}
279+
} zend_catch {
280+
php_session_cancel_decode();
281+
zend_bailout();
282+
} zend_end_try();
273283
return SUCCESS;
274284
}
275285
/* }}} */

ext/session/tests/gh12504.phpt

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
--TEST--
2+
GH-12504 (Corrupted session written when there's a fatal error in autoloader)
3+
--EXTENSIONS--
4+
session
5+
--FILE--
6+
<?php
7+
8+
class TestSessionHandler implements SessionHandlerInterface
9+
{
10+
public function close(): bool
11+
{
12+
return true;
13+
}
14+
public function destroy(string $id): bool
15+
{
16+
return true;
17+
}
18+
public function gc(int $max_lifetime): int|false
19+
{
20+
return 0;
21+
}
22+
public function open(string $path, string $name): bool
23+
{
24+
return true;
25+
}
26+
public function read(string $id): string|false
27+
{
28+
// Return a session object that has 3 variables
29+
return 'before|i:1234;test|O:4:"Test":0:{}after|i:5678;';
30+
}
31+
public function write($id, $data): bool
32+
{
33+
echo 'Write session:' . PHP_EOL;
34+
echo $data . PHP_EOL;
35+
return true;
36+
}
37+
}
38+
39+
register_shutdown_function(function() {
40+
echo "In shutdown function\n";
41+
var_dump($_SESSION);
42+
});
43+
44+
session_set_save_handler(new TestSessionHandler());
45+
46+
// Autoload class that's in session
47+
spl_autoload_register(function() {
48+
// Easiest way to reproduce the issue is to dynamically define a class with a bogus definition
49+
eval('class Test {public int $var = null;}');
50+
return true;
51+
});
52+
53+
session_start();
54+
55+
?>
56+
--EXPECTF--
57+
Fatal error: Default value for property of type int may not be null. Use the nullable type ?int to allow null default value in %s on line %d
58+
59+
Warning: Unknown: Failed to decode session object. Session has been destroyed in Unknown on line 0
60+
In shutdown function
61+
array(0) {
62+
}

0 commit comments

Comments
 (0)