Skip to content

Commit c0de721

Browse files
committed
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.
1 parent d6efff7 commit c0de721

File tree

7 files changed

+85
-2
lines changed

7 files changed

+85
-2
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ PHP NEWS
1313
. Fixed case when curl_error returns an empty string.
1414
(David Carlier)
1515

16+
- FFI:
17+
. Fixed bug GH-14286 (ffi enum type (when enum has no name) make memory
18+
leak). (nielsdos, dstogov)
19+
1620
- Soap:
1721
. Fixed bug #55639 (Digest autentication dont work). (nielsdos)
1822

ext/ffi/ffi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3544,7 +3544,7 @@ ZEND_METHOD(FFI, scope) /* {{{ */
35443544
}
35453545
/* }}} */
35463546

3547-
static void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl) /* {{{ */
3547+
void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl) /* {{{ */
35483548
{
35493549
if (dcl) {
35503550
zend_ffi_type_dtor(dcl->type);

ext/ffi/ffi.g

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ declarations:
9797
initializer?
9898
{zend_ffi_declare(name, name_len, &dcl);}
9999
)*
100-
)?
100+
|
101+
/* empty */
102+
{if (common_dcl.flags & (ZEND_FFI_DCL_ENUM | ZEND_FFI_DCL_STRUCT | ZEND_FFI_DCL_UNION)) zend_ffi_cleanup_dcl(&common_dcl);}
103+
)
101104
";"
102105
)*
103106
;

ext/ffi/ffi_parser.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,10 @@ static int parse_declarations(int sym) {
21152115
}
21162116
zend_ffi_declare(name, name_len, &dcl);
21172117
}
2118+
} else if (sym == YY__SEMICOLON) {
2119+
if (common_dcl.flags & (ZEND_FFI_DCL_ENUM | ZEND_FFI_DCL_STRUCT | ZEND_FFI_DCL_UNION)) zend_ffi_cleanup_dcl(&common_dcl);
2120+
} else {
2121+
yy_error_sym("unexpected", sym);
21182122
}
21192123
if (sym != YY__SEMICOLON) {
21202124
yy_error_sym("';' expected, got", sym);

ext/ffi/php_ffi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ typedef struct _zend_ffi_val {
208208

209209
zend_result zend_ffi_parse_decl(const char *str, size_t len);
210210
zend_result zend_ffi_parse_type(const char *str, size_t len, zend_ffi_dcl *dcl);
211+
void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl);
211212

212213
/* parser callbacks */
213214
void ZEND_NORETURN zend_ffi_parser_error(const char *msg, ...);

ext/ffi/tests/gh14286_1.phpt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--TEST--
2+
GH-14286 (ffi enum type (when enum has no name) make memory leak)
3+
--EXTENSIONS--
4+
ffi
5+
--INI--
6+
ffi.enable=1
7+
--FILE--
8+
<?php
9+
$ffi = FFI::cdef("
10+
enum {
11+
TEST_ONE=1,
12+
TEST_TWO=2,
13+
};
14+
enum TestEnum {
15+
TEST_THREE=3,
16+
};
17+
struct TestStruct {
18+
enum {
19+
TEST_FOUR=4,
20+
} test1;
21+
enum TestEnum2 {
22+
TEST_FIVE=5,
23+
} test2;
24+
};
25+
typedef enum { TEST_SIX=6 } TestEnum3;
26+
struct {
27+
int x;
28+
};
29+
union {
30+
int x;
31+
};
32+
");
33+
var_dump($ffi->TEST_ONE);
34+
var_dump($ffi->TEST_TWO);
35+
var_dump($ffi->TEST_THREE);
36+
var_dump($ffi->TEST_FOUR);
37+
var_dump($ffi->TEST_FIVE);
38+
var_dump($ffi->TEST_SIX);
39+
?>
40+
--EXPECT--
41+
int(1)
42+
int(2)
43+
int(3)
44+
int(4)
45+
int(5)
46+
int(6)

ext/ffi/tests/gh14286_2.phpt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
GH-14286 (ffi enum type (when enum has no name) make memory leak)
3+
--EXTENSIONS--
4+
ffi
5+
--SKIPIF--
6+
<?php
7+
if (PHP_DEBUG || getenv('SKIP_ASAN')) die("xfail: FFI cleanup after parser error is nor implemented");
8+
?>
9+
--INI--
10+
ffi.enable=1
11+
--FILE--
12+
<?php
13+
try {
14+
$ffi = FFI::cdef("
15+
enum {
16+
TEST_ONE=1,
17+
TEST_TWO=2,
18+
} x;
19+
");
20+
} catch (Throwable $e) {
21+
echo $e->getMessage(), "\n";
22+
}
23+
?>
24+
--EXPECT--
25+
Failed resolving C variable 'x'

0 commit comments

Comments
 (0)