Skip to content

Commit 11d6bea

Browse files
committed
Fix leaking definitions on FFI::cdef()->new()
Previously, FFI_G(symbols) and FFI_G(tags) were never cleaned up when calling new on an existing object. However, if cdef() is called without parameters these globals are NULL and might be created when new() creates new definitions. These would then be discarded without freeing them. Closes GH-11751
1 parent 6e3c520 commit 11d6bea

File tree

3 files changed

+69
-60
lines changed

3 files changed

+69
-60
lines changed

NEWS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.1.23
44

5-
5+
- FFI:
6+
. Fix leaking definitions when using FFI::cdef()->new(...). (ilutov)
67

78
03 Aug 2023, PHP 8.1.22
89

ext/ffi/ffi.c

Lines changed: 53 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3684,22 +3684,22 @@ ZEND_METHOD(FFI, new) /* {{{ */
36843684
FFI_G(symbols) = NULL;
36853685
FFI_G(tags) = NULL;
36863686
}
3687+
bool clean_symbols = FFI_G(symbols) == NULL;
3688+
bool clean_tags = FFI_G(tags) == NULL;
36873689

36883690
FFI_G(default_type_attr) = 0;
36893691

36903692
if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) != SUCCESS) {
36913693
zend_ffi_type_dtor(dcl.type);
3692-
if (Z_TYPE(EX(This)) != IS_OBJECT) {
3693-
if (FFI_G(tags)) {
3694-
zend_hash_destroy(FFI_G(tags));
3695-
efree(FFI_G(tags));
3696-
FFI_G(tags) = NULL;
3697-
}
3698-
if (FFI_G(symbols)) {
3699-
zend_hash_destroy(FFI_G(symbols));
3700-
efree(FFI_G(symbols));
3701-
FFI_G(symbols) = NULL;
3702-
}
3694+
if (clean_tags && FFI_G(tags)) {
3695+
zend_hash_destroy(FFI_G(tags));
3696+
efree(FFI_G(tags));
3697+
FFI_G(tags) = NULL;
3698+
}
3699+
if (clean_symbols && FFI_G(symbols)) {
3700+
zend_hash_destroy(FFI_G(symbols));
3701+
efree(FFI_G(symbols));
3702+
FFI_G(symbols) = NULL;
37033703
}
37043704
return;
37053705
}
@@ -3709,15 +3709,13 @@ ZEND_METHOD(FFI, new) /* {{{ */
37093709
is_const = 1;
37103710
}
37113711

3712-
if (Z_TYPE(EX(This)) != IS_OBJECT) {
3713-
if (FFI_G(tags)) {
3714-
zend_ffi_tags_cleanup(&dcl);
3715-
}
3716-
if (FFI_G(symbols)) {
3717-
zend_hash_destroy(FFI_G(symbols));
3718-
efree(FFI_G(symbols));
3719-
FFI_G(symbols) = NULL;
3720-
}
3712+
if (clean_tags && FFI_G(tags)) {
3713+
zend_ffi_tags_cleanup(&dcl);
3714+
}
3715+
if (clean_symbols && FFI_G(symbols)) {
3716+
zend_hash_destroy(FFI_G(symbols));
3717+
efree(FFI_G(symbols));
3718+
FFI_G(symbols) = NULL;
37213719
}
37223720
FFI_G(symbols) = NULL;
37233721
FFI_G(tags) = NULL;
@@ -3828,22 +3826,22 @@ ZEND_METHOD(FFI, cast) /* {{{ */
38283826
FFI_G(symbols) = NULL;
38293827
FFI_G(tags) = NULL;
38303828
}
3829+
bool clean_symbols = FFI_G(symbols) == NULL;
3830+
bool clean_tags = FFI_G(tags) == NULL;
38313831

38323832
FFI_G(default_type_attr) = 0;
38333833

38343834
if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) != SUCCESS) {
38353835
zend_ffi_type_dtor(dcl.type);
3836-
if (Z_TYPE(EX(This)) != IS_OBJECT) {
3837-
if (FFI_G(tags)) {
3838-
zend_hash_destroy(FFI_G(tags));
3839-
efree(FFI_G(tags));
3840-
FFI_G(tags) = NULL;
3841-
}
3842-
if (FFI_G(symbols)) {
3843-
zend_hash_destroy(FFI_G(symbols));
3844-
efree(FFI_G(symbols));
3845-
FFI_G(symbols) = NULL;
3846-
}
3836+
if (clean_tags && FFI_G(tags)) {
3837+
zend_hash_destroy(FFI_G(tags));
3838+
efree(FFI_G(tags));
3839+
FFI_G(tags) = NULL;
3840+
}
3841+
if (clean_symbols && FFI_G(symbols)) {
3842+
zend_hash_destroy(FFI_G(symbols));
3843+
efree(FFI_G(symbols));
3844+
FFI_G(symbols) = NULL;
38473845
}
38483846
return;
38493847
}
@@ -3853,15 +3851,13 @@ ZEND_METHOD(FFI, cast) /* {{{ */
38533851
is_const = 1;
38543852
}
38553853

3856-
if (Z_TYPE(EX(This)) != IS_OBJECT) {
3857-
if (FFI_G(tags)) {
3858-
zend_ffi_tags_cleanup(&dcl);
3859-
}
3860-
if (FFI_G(symbols)) {
3861-
zend_hash_destroy(FFI_G(symbols));
3862-
efree(FFI_G(symbols));
3863-
FFI_G(symbols) = NULL;
3864-
}
3854+
if (clean_tags && FFI_G(tags)) {
3855+
zend_ffi_tags_cleanup(&dcl);
3856+
}
3857+
if (clean_symbols && FFI_G(symbols)) {
3858+
zend_hash_destroy(FFI_G(symbols));
3859+
efree(FFI_G(symbols));
3860+
FFI_G(symbols) = NULL;
38653861
}
38663862
FFI_G(symbols) = NULL;
38673863
FFI_G(tags) = NULL;
@@ -3994,35 +3990,33 @@ ZEND_METHOD(FFI, type) /* {{{ */
39943990
FFI_G(symbols) = NULL;
39953991
FFI_G(tags) = NULL;
39963992
}
3993+
bool clean_symbols = FFI_G(symbols) == NULL;
3994+
bool clean_tags = FFI_G(tags) == NULL;
39973995

39983996
FFI_G(default_type_attr) = 0;
39993997

40003998
if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) != SUCCESS) {
40013999
zend_ffi_type_dtor(dcl.type);
4002-
if (Z_TYPE(EX(This)) != IS_OBJECT) {
4003-
if (FFI_G(tags)) {
4004-
zend_hash_destroy(FFI_G(tags));
4005-
efree(FFI_G(tags));
4006-
FFI_G(tags) = NULL;
4007-
}
4008-
if (FFI_G(symbols)) {
4009-
zend_hash_destroy(FFI_G(symbols));
4010-
efree(FFI_G(symbols));
4011-
FFI_G(symbols) = NULL;
4012-
}
4013-
}
4014-
return;
4015-
}
4016-
4017-
if (Z_TYPE(EX(This)) != IS_OBJECT) {
4018-
if (FFI_G(tags)) {
4019-
zend_ffi_tags_cleanup(&dcl);
4000+
if (clean_tags && FFI_G(tags)) {
4001+
zend_hash_destroy(FFI_G(tags));
4002+
efree(FFI_G(tags));
4003+
FFI_G(tags) = NULL;
40204004
}
4021-
if (FFI_G(symbols)) {
4005+
if (clean_symbols && FFI_G(symbols)) {
40224006
zend_hash_destroy(FFI_G(symbols));
40234007
efree(FFI_G(symbols));
40244008
FFI_G(symbols) = NULL;
40254009
}
4010+
return;
4011+
}
4012+
4013+
if (clean_tags && FFI_G(tags)) {
4014+
zend_ffi_tags_cleanup(&dcl);
4015+
}
4016+
if (clean_symbols && FFI_G(symbols)) {
4017+
zend_hash_destroy(FFI_G(symbols));
4018+
efree(FFI_G(symbols));
4019+
FFI_G(symbols) = NULL;
40264020
}
40274021
FFI_G(symbols) = NULL;
40284022
FFI_G(tags) = NULL;

ext/ffi/tests/cdef_new.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Definitions should not leak when using FFI::cdef()->new(...)
3+
--EXTENSIONS--
4+
ffi
5+
--FILE--
6+
<?php
7+
$struct = \FFI::cdef()->new('struct Example { uint32_t x; }');
8+
var_dump($struct);
9+
?>
10+
--EXPECT--
11+
object(FFI\CData:struct Example)#2 (1) {
12+
["x"]=>
13+
int(0)
14+
}

0 commit comments

Comments
 (0)