Skip to content

Commit f1333bc

Browse files
committed
Merge branch 'PHP-8.2'
* PHP-8.2: Reset EG(trampoline).op_array.last_var that FFI may modify
2 parents 42ecd88 + 69c57be commit f1333bc

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

Zend/zend_object_handlers.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,12 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce
13131313
ZEND_MAP_PTR_INIT(func->run_time_cache, (void**)dummy);
13141314
func->scope = fbc->common.scope;
13151315
/* reserve space for arguments, local and temporary variables */
1316+
/* EG(trampoline) is reused from other places, like FFI (e.g. zend_ffi_cdata_get_closure()) where
1317+
* it is used as an internal function. It may set fields that don't belong to common, thus
1318+
* modifying zend_op_array specific data, most significantly last_var. We need to reset this
1319+
* value so that it doesn't contain garbage when the engine allocates space for the next stack
1320+
* frame. This didn't cause any issues until now due to "lucky" structure layout. */
1321+
func->last_var = 0;
13161322
func->T = (fbc->type == ZEND_USER_FUNCTION)? MAX(fbc->op_array.last_var + fbc->op_array.T, 2) : 2;
13171323
func->filename = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.filename : ZSTR_EMPTY_ALLOC();
13181324
func->line_start = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_start : 0;

ext/ffi/tests/trampoline_reset.phpt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
Memory corruption when mixing __callStatic() and FFI
3+
--EXTENSIONS--
4+
ffi
5+
--SKIPIF--
6+
<?php
7+
try {
8+
$libc = FFI::cdef("int printf(const char *format, ...);", "libc.so.6");
9+
} catch (Throwable $_) {
10+
die('skip libc.so.6 not available');
11+
}
12+
?>
13+
--INI--
14+
ffi.enable=1
15+
--FILE--
16+
<?php
17+
class Test
18+
{
19+
public static function __callStatic($name, $args)
20+
{
21+
echo "$name called\n";
22+
}
23+
}
24+
25+
$header = '
26+
typedef struct _IO_FILE FILE;
27+
extern FILE *stdout;
28+
int fprintf(FILE *, const char *, ...);
29+
int fflush(FILE *);
30+
';
31+
$ffi = FFI::cdef($header, 'libc.so.6');
32+
33+
Test::foo();
34+
Test::bar();
35+
$ffi->fprintf($ffi->stdout, "FFI\n");
36+
$ffi->fflush($ffi->stdout);
37+
Test::baz();
38+
?>
39+
--EXPECT--
40+
foo called
41+
bar called
42+
FFI
43+
baz called

0 commit comments

Comments
 (0)