1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Merge branch 'PHP-8.5'

* PHP-8.5:
  ext/ffi: Fix resource leak in FFI::cdef() on symbol resolution failure.
This commit is contained in:
David Carlier
2026-03-22 21:58:09 +00:00
4 changed files with 56 additions and 25 deletions

View File

@@ -1253,10 +1253,8 @@ static zval *zend_ffi_cdata_read_field(zend_object *obj, zend_string *field_name
type = ZEND_FFI_TYPE(type->pointer.type); type = ZEND_FFI_TYPE(type->pointer.type);
} }
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) { if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) { zend_throw_error(zend_ffi_exception_ce, "Attempt to read field '%s' of non C struct/union", ZSTR_VAL(field_name));
zend_throw_error(zend_ffi_exception_ce, "Attempt to read field '%s' of non C struct/union", ZSTR_VAL(field_name)); return &EG(uninitialized_zval);
return &EG(uninitialized_zval);
}
} }
field = zend_hash_find_ptr(&type->record.fields, field_name); field = zend_hash_find_ptr(&type->record.fields, field_name);
@@ -1331,10 +1329,8 @@ static zval *zend_ffi_cdata_write_field(zend_object *obj, zend_string *field_nam
type = ZEND_FFI_TYPE(type->pointer.type); type = ZEND_FFI_TYPE(type->pointer.type);
} }
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) { if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) { zend_throw_error(zend_ffi_exception_ce, "Attempt to assign field '%s' of non C struct/union", ZSTR_VAL(field_name));
zend_throw_error(zend_ffi_exception_ce, "Attempt to assign field '%s' of non C struct/union", ZSTR_VAL(field_name)); return value;
return value;
}
} }
field = zend_hash_find_ptr(&type->record.fields, field_name); field = zend_hash_find_ptr(&type->record.fields, field_name);
@@ -3107,17 +3103,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
FFI_G(default_type_attr) = ZEND_FFI_ATTR_STORED; FFI_G(default_type_attr) = ZEND_FFI_ATTR_STORED;
if (zend_ffi_parse_decl(ZSTR_VAL(code), ZSTR_LEN(code)) == FAILURE) { if (zend_ffi_parse_decl(ZSTR_VAL(code), ZSTR_LEN(code)) == FAILURE) {
if (FFI_G(symbols)) { goto cleanup;
zend_hash_destroy(FFI_G(symbols));
efree(FFI_G(symbols));
FFI_G(symbols) = NULL;
}
if (FFI_G(tags)) {
zend_hash_destroy(FFI_G(tags));
efree(FFI_G(tags));
FFI_G(tags) = NULL;
}
RETURN_THROWS();
} }
if (FFI_G(symbols)) { if (FFI_G(symbols)) {
@@ -3130,7 +3116,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name)); addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
if (!addr) { if (!addr) {
zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name)); zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name));
RETURN_THROWS(); goto cleanup;
} }
sym->addr = addr; sym->addr = addr;
} else if (sym->kind == ZEND_FFI_SYM_FUNC) { } else if (sym->kind == ZEND_FFI_SYM_FUNC) {
@@ -3140,7 +3126,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
zend_string_release(mangled_name); zend_string_release(mangled_name);
if (!addr) { if (!addr) {
zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name)); zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name));
RETURN_THROWS(); goto cleanup;
} }
sym->addr = addr; sym->addr = addr;
} }
@@ -3157,6 +3143,22 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
FFI_G(tags) = NULL; FFI_G(tags) = NULL;
RETURN_OBJ(&ffi->std); RETURN_OBJ(&ffi->std);
cleanup:
if (lib && handle) {
DL_UNLOAD(handle);
}
if (FFI_G(symbols)) {
zend_hash_destroy(FFI_G(symbols));
efree(FFI_G(symbols));
FFI_G(symbols) = NULL;
}
if (FFI_G(tags)) {
zend_hash_destroy(FFI_G(tags));
efree(FFI_G(tags));
FFI_G(tags) = NULL;
}
RETURN_THROWS();
} }
/* }}} */ /* }}} */

View File

@@ -2,10 +2,6 @@
GH-14286 (ffi enum type (when enum has no name) make memory leak) GH-14286 (ffi enum type (when enum has no name) make memory leak)
--EXTENSIONS-- --EXTENSIONS--
ffi ffi
--SKIPIF--
<?php
if (PHP_DEBUG || getenv('SKIP_ASAN')) die("xfail: FFI cleanup after parser error is not implemented");
?>
--INI-- --INI--
ffi.enable=1 ffi.enable=1
--FILE-- --FILE--

View File

@@ -0,0 +1,16 @@
--TEST--
GH-18629 (FFI::cdef() leaks on function resolution failure)
--EXTENSIONS--
ffi
--INI--
ffi.enable=1
--FILE--
<?php
try {
$ffi = FFI::cdef("void nonexistent_ffi_test_func(void);");
} catch (\FFI\Exception $e) {
echo $e->getMessage() . "\n";
}
?>
--EXPECT--
Failed resolving C function 'nonexistent_ffi_test_func'

View File

@@ -0,0 +1,17 @@
--TEST--
GH-18629 (Read field of non C struct/union)
--EXTENSIONS--
ffi
--INI--
ffi.enable=1
--FILE--
<?php
$x = FFI::cdef()->new("int*");
try {
$y = $x->foo;
} catch (\FFI\Exception $e) {
echo $e->getMessage() . "\n";
}
?>
--EXPECT--
Attempt to read field 'foo' of non C struct/union