Skip to content

Commit b6b26f4

Browse files
committed
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4: ext/ffi: Fix resource leak in FFI::cdef() on symbol resolution failure.
2 parents 99365b8 + 97bb48e commit b6b26f4

File tree

5 files changed

+60
-25
lines changed

5 files changed

+60
-25
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ PHP NEWS
1515
. Fixed bug GH-21486 (Dom\HTMLDocument parser mangles xml:space and
1616
xml:lang attributes). (ndossche)
1717

18+
- FFI:
19+
. Fixed resource leak in FFI::cdef() onsymbol resolution failure.
20+
(David Carlier)
21+
1822
- GD:
1923
. Fixed bug GH-21431 (phpinfo() to display libJPEG 10.0 support).
2024
(David Carlier)

ext/ffi/ffi.c

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,10 +1252,8 @@ static zval *zend_ffi_cdata_read_field(zend_object *obj, zend_string *field_name
12521252
type = ZEND_FFI_TYPE(type->pointer.type);
12531253
}
12541254
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1255-
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1256-
zend_throw_error(zend_ffi_exception_ce, "Attempt to read field '%s' of non C struct/union", ZSTR_VAL(field_name));
1257-
return &EG(uninitialized_zval);
1258-
}
1255+
zend_throw_error(zend_ffi_exception_ce, "Attempt to read field '%s' of non C struct/union", ZSTR_VAL(field_name));
1256+
return &EG(uninitialized_zval);
12591257
}
12601258

12611259
field = zend_hash_find_ptr(&type->record.fields, field_name);
@@ -1329,10 +1327,8 @@ static zval *zend_ffi_cdata_write_field(zend_object *obj, zend_string *field_nam
13291327
type = ZEND_FFI_TYPE(type->pointer.type);
13301328
}
13311329
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1332-
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1333-
zend_throw_error(zend_ffi_exception_ce, "Attempt to assign field '%s' of non C struct/union", ZSTR_VAL(field_name));
1334-
return value;
1335-
}
1330+
zend_throw_error(zend_ffi_exception_ce, "Attempt to assign field '%s' of non C struct/union", ZSTR_VAL(field_name));
1331+
return value;
13361332
}
13371333

13381334
field = zend_hash_find_ptr(&type->record.fields, field_name);
@@ -3098,17 +3094,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
30983094
FFI_G(default_type_attr) = ZEND_FFI_ATTR_STORED;
30993095

31003096
if (zend_ffi_parse_decl(ZSTR_VAL(code), ZSTR_LEN(code)) == FAILURE) {
3101-
if (FFI_G(symbols)) {
3102-
zend_hash_destroy(FFI_G(symbols));
3103-
efree(FFI_G(symbols));
3104-
FFI_G(symbols) = NULL;
3105-
}
3106-
if (FFI_G(tags)) {
3107-
zend_hash_destroy(FFI_G(tags));
3108-
efree(FFI_G(tags));
3109-
FFI_G(tags) = NULL;
3110-
}
3111-
RETURN_THROWS();
3097+
goto cleanup;
31123098
}
31133099

31143100
if (FFI_G(symbols)) {
@@ -3121,7 +3107,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
31213107
addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
31223108
if (!addr) {
31233109
zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name));
3124-
RETURN_THROWS();
3110+
goto cleanup;
31253111
}
31263112
sym->addr = addr;
31273113
} else if (sym->kind == ZEND_FFI_SYM_FUNC) {
@@ -3131,7 +3117,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
31313117
zend_string_release(mangled_name);
31323118
if (!addr) {
31333119
zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name));
3134-
RETURN_THROWS();
3120+
goto cleanup;
31353121
}
31363122
sym->addr = addr;
31373123
}
@@ -3148,6 +3134,22 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
31483134
FFI_G(tags) = NULL;
31493135

31503136
RETURN_OBJ(&ffi->std);
3137+
3138+
cleanup:
3139+
if (lib && handle) {
3140+
DL_UNLOAD(handle);
3141+
}
3142+
if (FFI_G(symbols)) {
3143+
zend_hash_destroy(FFI_G(symbols));
3144+
efree(FFI_G(symbols));
3145+
FFI_G(symbols) = NULL;
3146+
}
3147+
if (FFI_G(tags)) {
3148+
zend_hash_destroy(FFI_G(tags));
3149+
efree(FFI_G(tags));
3150+
FFI_G(tags) = NULL;
3151+
}
3152+
RETURN_THROWS();
31513153
}
31523154
/* }}} */
31533155

ext/ffi/tests/gh14286_2.phpt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22
GH-14286 (ffi enum type (when enum has no name) make memory leak)
33
--EXTENSIONS--
44
ffi
5-
--SKIPIF--
6-
<?php
7-
if (PHP_DEBUG || getenv('SKIP_ASAN')) die("xfail: FFI cleanup after parser error is not implemented");
8-
?>
95
--INI--
106
ffi.enable=1
117
--FILE--
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
GH-18629 (FFI::cdef() leaks on function resolution failure)
3+
--EXTENSIONS--
4+
ffi
5+
--INI--
6+
ffi.enable=1
7+
--FILE--
8+
<?php
9+
try {
10+
$ffi = FFI::cdef("void nonexistent_ffi_test_func(void);");
11+
} catch (\FFI\Exception $e) {
12+
echo $e->getMessage() . "\n";
13+
}
14+
?>
15+
--EXPECT--
16+
Failed resolving C function 'nonexistent_ffi_test_func'
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
GH-18629 (Read field of non C struct/union)
3+
--EXTENSIONS--
4+
ffi
5+
--INI--
6+
ffi.enable=1
7+
--FILE--
8+
<?php
9+
$x = FFI::cdef()->new("int*");
10+
try {
11+
$y = $x->foo;
12+
} catch (\FFI\Exception $e) {
13+
echo $e->getMessage() . "\n";
14+
}
15+
?>
16+
--EXPECT--
17+
Attempt to read field 'foo' of non C struct/union

0 commit comments

Comments
 (0)