diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 560338e71f33..8b0b58105d32 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 b70e3f129962..6628386a5079 100644 --- a/ext/ffi/ffi.g +++ b/ext/ffi/ffi.g @@ -96,7 +96,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 b956f885ee00..94d50d59b5d3 100644 --- a/ext/ffi/ffi_parser.c +++ b/ext/ffi/ffi_parser.c @@ -2056,6 +2056,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 02a241c6bb69..430b8a2e568f 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 000000000000..19701f634a63 --- /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 000000000000..683929780c05 --- /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'