[php-src] PR #24591: Fix GH-24582: Memory leaks in ext/ffi parser when finalize_type() bails out

From: Date: Fri, 23 Oct 2026 09:07:41 +0000
Subject: [php-src] PR #24591: Fix GH-24582: Memory leaks in ext/ffi parser when finalize_type() bails out
Groups: php.git-pulls 
Request: Send a blank email to git-pulls+get-39756@lists.php.net to get a copy of this message
Pull Request: https://github.com/php/php-src/pull/24591 Author: matyapiro31 ### Problem zend_ffi_finalize_type() calls zend_ffi_parser_error() for unsupported specifier combinations, which always ends in LONGJMP(FFI_G(bailout), FAILURE). It only does so when dcl->type == NULL, so dcl owns nothing, but four callbacks own other memory at that point: | callback | leaked | |---|---| | zend_ffi_make_pointer_type() | the type it had just allocated | | zend_ffi_make_func_type() | args, nested_dcl | | zend_ffi_add_arg() | *args, including the arguments collected so far | | zend_ffi_nested_declaration() | nested_dcl | Reproducer (a debug build reports it at shutdown): ```php FFI::cdef("double _Complex *x;"); // FFI\ParserException: Unsupported type _Complex ``` ### Change - zend_ffi_try_finalize_type() throws the parser exception and returns FAILURE, like the zend_ffi_validate_* helpers. zend_ffi_finalize_type() stays as a wrapper that bails out, so the other callers are not touched. - The four callbacks use the new function and release what they own before LONGJMP, with the same calls the later error paths of the same functions already use. - zend_ffi_make_pointer_type() allocates after the checks, as zend_ffi_make_array_type() does. ### Testing Debug ZTS build on 8.4.28-dev (Windows, Visual C++ 2022): - New test ext/ffi/tests/finalize_type_bailout_leak.phpt checks the exception message and that memory_get_usage() does not grow, so it also detects the leak on non-debug builds. Without the fix it reports a leak for all seven declarations; with the fix it passes. - ext/ffi suite: 87 passed, 0 failed (24 skipped, no libc.so.6 on Windows). - Double free: the default debug allocator does not detect a double free (I checked with a deliberate one), so I also ran the suite and 42 declarations x 300 runs with USE_ZEND_ALLOC=0: no crash. - 42 declarations (nested declarators, function pointers, struct fields, typedefs, valid controls), one process each: unpatched 33 leak, patched 10; 23 fully fixed, 7 reduced, none worse. ### Not covered Ten of those declarations still leak. The cause is different: a callee bails out while an enclosing declarator (nested_dcl of parse_declarator(), or the dcl of an outer *) owns a type the callee cannot reach, for example double _Complex (*x)[3];, int *f(double _Complex x); and, without _Complex, int *f(@);. A proper fix needs to be at the parser level; see the discussion in GH-24582. If that is the direction, the cleanups here have to be dropped with it to avoid releasing a type twice. The persistent (ffi.preload) path was not run (no opcache in my build); the new code uses the same FFI_G(persistent) expressions as the existing error paths. 🤖 Generated with [Claude Code](https://claude.com/claude-code) ✔ Checked by me.

« previous php.git-pulls (#39756) next »