From c0de7214aa9a2d9f03ce3fe4c6c02667fa3c8672 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 6 Jul 2024 01:10:04 +0200 Subject: [PATCH] Fix GH-14286 (ffi enum type (when enum has no name) make memory leak) For top-level anonymous type definition we never store the declaration anywhere else nor the type anywhere else. The declaration keeps owning the type and it goes out of scope. For anonymous fields this gets handled by the add_anonymous_field code that removes the type from the declaration. This patch does something similar in the parsing code when it is detected we're dealing with an anonymous enum in a top-level declaration. Closes GH-14839. --- NEWS | 4 ++++ ext/ffi/ffi.c | 2 +- ext/ffi/ffi.g | 5 +++- ext/ffi/ffi_parser.c | 4 ++++ ext/ffi/php_ffi.h | 1 + ext/ffi/tests/gh14286_1.phpt | 46 ++++++++++++++++++++++++++++++++++++ ext/ffi/tests/gh14286_2.phpt | 25 ++++++++++++++++++++ 7 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 ext/ffi/tests/gh14286_1.phpt create mode 100644 ext/ffi/tests/gh14286_2.phpt diff --git a/NEWS b/NEWS index 11ff5add75a..828a8fdff31 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,10 @@ PHP NEWS . Fixed case when curl_error returns an empty string. (David Carlier) +- FFI: + . Fixed bug GH-14286 (ffi enum type (when enum has no name) make memory + leak). (nielsdos, dstogov) + - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 560338e71f3..8b0b58105d3 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -3544,7 +3544,7 @@ ZEND_METHOD(FFI, scope) /* {{{ */ } /* }}} */ -static void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl) /* {{{ */ +void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl) /* {{{ */ { if (dcl) { zend_ffi_type_dtor(dcl->type); diff --git a/ext/ffi/ffi.g b/ext/ffi/ffi.g index e30d86b21c7..d70075267e5 100644 --- a/ext/ffi/ffi.g +++ b/ext/ffi/ffi.g @@ -97,7 +97,10 @@ declarations: initializer? {zend_ffi_declare(name, name_len, &dcl);} )* - )? + | + /* empty */ + {if (common_dcl.flags & (ZEND_FFI_DCL_ENUM | ZEND_FFI_DCL_STRUCT | ZEND_FFI_DCL_UNION)) zend_ffi_cleanup_dcl(&common_dcl);} + ) ";" )* ; diff --git a/ext/ffi/ffi_parser.c b/ext/ffi/ffi_parser.c index 8d06f1d8758..2589ae81e02 100644 --- a/ext/ffi/ffi_parser.c +++ b/ext/ffi/ffi_parser.c @@ -2115,6 +2115,10 @@ static int parse_declarations(int sym) { } zend_ffi_declare(name, name_len, &dcl); } + } else if (sym == YY__SEMICOLON) { + if (common_dcl.flags & (ZEND_FFI_DCL_ENUM | ZEND_FFI_DCL_STRUCT | ZEND_FFI_DCL_UNION)) zend_ffi_cleanup_dcl(&common_dcl); + } else { + yy_error_sym("unexpected", sym); } if (sym != YY__SEMICOLON) { yy_error_sym("';' expected, got", sym); diff --git a/ext/ffi/php_ffi.h b/ext/ffi/php_ffi.h index 02a241c6bb6..430b8a2e568 100644 --- a/ext/ffi/php_ffi.h +++ b/ext/ffi/php_ffi.h @@ -208,6 +208,7 @@ typedef struct _zend_ffi_val { zend_result zend_ffi_parse_decl(const char *str, size_t len); zend_result zend_ffi_parse_type(const char *str, size_t len, zend_ffi_dcl *dcl); +void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl); /* parser callbacks */ void ZEND_NORETURN zend_ffi_parser_error(const char *msg, ...); diff --git a/ext/ffi/tests/gh14286_1.phpt b/ext/ffi/tests/gh14286_1.phpt new file mode 100644 index 00000000000..19701f634a6 --- /dev/null +++ b/ext/ffi/tests/gh14286_1.phpt @@ -0,0 +1,46 @@ +--TEST-- +GH-14286 (ffi enum type (when enum has no name) make memory leak) +--EXTENSIONS-- +ffi +--INI-- +ffi.enable=1 +--FILE-- +TEST_ONE); +var_dump($ffi->TEST_TWO); +var_dump($ffi->TEST_THREE); +var_dump($ffi->TEST_FOUR); +var_dump($ffi->TEST_FIVE); +var_dump($ffi->TEST_SIX); +?> +--EXPECT-- +int(1) +int(2) +int(3) +int(4) +int(5) +int(6) diff --git a/ext/ffi/tests/gh14286_2.phpt b/ext/ffi/tests/gh14286_2.phpt new file mode 100644 index 00000000000..683929780c0 --- /dev/null +++ b/ext/ffi/tests/gh14286_2.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-14286 (ffi enum type (when enum has no name) make memory leak) +--EXTENSIONS-- +ffi +--SKIPIF-- + +--INI-- +ffi.enable=1 +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +Failed resolving C variable 'x'