Merge branch 'PHP-8.2'

* PHP-8.2:
  Reset EG(trampoline).op_array.last_var that FFI may modify
This commit is contained in:
Ilija Tovilo 2023-03-27 23:00:12 +02:00
commit f1333bc9fe
No known key found for this signature in database
GPG key ID: A4F5D403F118200A
2 changed files with 49 additions and 0 deletions

View file

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

View file

@ -0,0 +1,43 @@
--TEST--
Memory corruption when mixing __callStatic() and FFI
--EXTENSIONS--
ffi
--SKIPIF--
<?php
try {
$libc = FFI::cdef("int printf(const char *format, ...);", "libc.so.6");
} catch (Throwable $_) {
die('skip libc.so.6 not available');
}
?>
--INI--
ffi.enable=1
--FILE--
<?php
class Test
{
public static function __callStatic($name, $args)
{
echo "$name called\n";
}
}
$header = '
typedef struct _IO_FILE FILE;
extern FILE *stdout;
int fprintf(FILE *, const char *, ...);
int fflush(FILE *);
';
$ffi = FFI::cdef($header, 'libc.so.6');
Test::foo();
Test::bar();
$ffi->fprintf($ffi->stdout, "FFI\n");
$ffi->fflush($ffi->stdout);
Test::baz();
?>
--EXPECT--
foo called
bar called
FFI
baz called