Skip to content

Commit 778ee69

Browse files
committed
Replace zend_get_gc_buffer_* with a Rust-owned trace buffer
Ubuntu's PHP 8.2 build (shivammathur/setup-php) does not export zend_get_gc_buffer_use, so the previous extern "C" declarations caused a link error at dlopen time. Drop them and own the trace buffer ourselves: a RefCell<Vec<zval>> on WpMySqlNativeAst that the get_gc handler refills on each call and exposes via the (table, n) out-params. Same semantics, no PHP-side dependency.
1 parent 89a4619 commit 778ee69

1 file changed

Lines changed: 38 additions & 31 deletions

File tree

  • packages/php-ext-wp-mysql-parser/src

packages/php-ext-wp-mysql-parser/src/lib.rs

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,6 @@ extern "C" {
3737
value: *mut zval,
3838
);
3939

40-
/// PHP's per-thread GC scratch buffer for `get_gc` handlers. The
41-
/// handler reports the object's outgoing references by adding zvals
42-
/// here, then `zend_get_gc_buffer_use` writes the buffer's contents
43-
/// into the (table, n) out-params the cycle collector reads.
44-
fn zend_get_gc_buffer_create() -> *mut std::ffi::c_void;
45-
fn zend_get_gc_buffer_add_zval(buffer: *mut std::ffi::c_void, zv: *mut zval);
46-
fn zend_get_gc_buffer_use(
47-
buffer: *mut std::ffi::c_void,
48-
table: *mut *mut zval,
49-
n: *mut std::os::raw::c_int,
50-
);
5140
}
5241

5342
/// `Z_TYPE_INFO` for an OBJECT zval that carries a refcount.
@@ -1079,6 +1068,13 @@ pub struct WpMySqlNativeAst {
10791068
/// bumped, skipping the allocation and four `zend_update_property`
10801069
/// calls of the construction path.
10811070
node_cache: RefCell<HashMap<usize, ZBox<ZendObject>>>,
1071+
/// Scratch buffer the custom `get_gc` handler refills on each
1072+
/// invocation with zvals pointing at every cached wrapper. We can't
1073+
/// use PHP's `zend_get_gc_buffer_*` API because PHP 8.2 builds on
1074+
/// Ubuntu's `shivammathur/setup-php` don't export those symbols, so
1075+
/// we own the buffer ourselves and hand its raw pointer to PHP via
1076+
/// the `(table, n)` out-params of the gc handler.
1077+
gc_trace: RefCell<Vec<zval>>,
10821078
}
10831079

10841080
impl NativeAstArena {
@@ -1274,27 +1270,37 @@ unsafe extern "C" fn ast_get_gc(
12741270
table: *mut *mut zval,
12751271
n: *mut std::os::raw::c_int,
12761272
) -> *mut HashTable {
1277-
let buf = zend_get_gc_buffer_create();
1278-
1279-
if let Some(ast) =
1280-
ext_php_rs::types::ZendClassObject::<WpMySqlNativeAst>::from_zend_obj(&*object)
1281-
.and_then(|z| z.obj.as_ref())
1282-
{
1283-
if let Ok(cache) = ast.node_cache.try_borrow() {
1284-
for boxed in cache.values() {
1285-
// Build a zval pointing at the cached wrapper without
1286-
// bumping refcount — the gc buffer just enumerates outgoing
1287-
// references; mutating refcounts here would un-balance the
1288-
// collector's accounting.
1289-
let mut zv: zval = std::mem::zeroed();
1290-
zv.value.obj = (boxed.as_ref() as *const ZendObject) as *mut zend_object as *mut _;
1291-
zv.u1.type_info = PHP_IS_OBJECT_EX;
1292-
zend_get_gc_buffer_add_zval(buf, &mut zv);
1293-
}
1294-
}
1295-
}
1273+
*table = std::ptr::null_mut();
1274+
*n = 0;
1275+
1276+
let Some(ast) = ext_php_rs::types::ZendClassObject::<WpMySqlNativeAst>::from_zend_obj(&*object)
1277+
.and_then(|z| z.obj.as_ref())
1278+
else {
1279+
return std::ptr::null_mut();
1280+
};
1281+
1282+
let Ok(cache) = ast.node_cache.try_borrow() else {
1283+
return std::ptr::null_mut();
1284+
};
1285+
let Ok(mut trace) = ast.gc_trace.try_borrow_mut() else {
1286+
return std::ptr::null_mut();
1287+
};
12961288

1297-
zend_get_gc_buffer_use(buf, table, n);
1289+
trace.clear();
1290+
trace.reserve(cache.len());
1291+
for boxed in cache.values() {
1292+
// Build a zval pointing at the cached wrapper without bumping
1293+
// refcount — the GC scan just enumerates outgoing references;
1294+
// mutating refcounts here would un-balance the collector's
1295+
// accounting.
1296+
let mut zv: zval = std::mem::zeroed();
1297+
zv.value.obj = (boxed.as_ref() as *const ZendObject) as *mut zend_object as *mut _;
1298+
zv.u1.type_info = PHP_IS_OBJECT_EX;
1299+
trace.push(zv);
1300+
}
1301+
1302+
*table = trace.as_mut_ptr();
1303+
*n = trace.len() as std::os::raw::c_int;
12981304
std::ptr::null_mut()
12991305
}
13001306

@@ -1932,6 +1938,7 @@ impl WpMySqlNativeParser {
19321938
let native_ast_zval = WpMySqlNativeAst {
19331939
arena,
19341940
node_cache: RefCell::new(HashMap::new()),
1941+
gc_trace: RefCell::new(Vec::new()),
19351942
}
19361943
.into_zval(false)
19371944
.map_err(php_error)?;

0 commit comments

Comments
 (0)