fix(types): better zval handling to avoid leaks with arrays (#1780)

This commit is contained in:
Alexandre Daubois
2025-08-04 19:00:13 +02:00
committed by GitHub
parent 365eae1a99
commit 1d0169d321
3 changed files with 39 additions and 27 deletions

14
types.c
View File

@@ -20,3 +20,17 @@ void __zend_hash_init__(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor,
bool persistent) { bool persistent) {
zend_hash_init(ht, nSize, NULL, pDestructor, persistent); zend_hash_init(ht, nSize, NULL, pDestructor, persistent);
} }
void __zval_null__(zval *zv) { ZVAL_NULL(zv); }
void __zval_bool__(zval *zv, bool val) { ZVAL_BOOL(zv, val); }
void __zval_long__(zval *zv, zend_long val) { ZVAL_LONG(zv, val); }
void __zval_double__(zval *zv, double val) { ZVAL_DOUBLE(zv, val); }
void __zval_string__(zval *zv, zend_string *str) { ZVAL_STR(zv, str); }
void __zval_arr__(zval *zv, zend_array *arr) { ZVAL_ARR(zv, arr); }
zend_array *__zend_new_array__(uint32_t size) { return zend_new_array(size); }

View File

@@ -179,8 +179,9 @@ func PHPArray(arr *Array) unsafe.Pointer {
zval := convertGoToZval(arr.values[i]) zval := convertGoToZval(arr.values[i])
if k.Type == PHPStringKey { if k.Type == PHPStringKey {
keyStr := PHPString(k.Str, false) keyStr := k.Str
C.zend_hash_update(zendArray, (*C.zend_string)(keyStr), zval) keyData := (*C.char)(unsafe.Pointer(unsafe.StringData(keyStr)))
C.zend_hash_str_add(zendArray, keyData, C.size_t(len(keyStr)), zval)
continue continue
} }
@@ -229,47 +230,36 @@ func convertZvalToGo(zval *C.zval) interface{} {
// convertGoToZval converts a Go interface{} to a PHP zval // convertGoToZval converts a Go interface{} to a PHP zval
func convertGoToZval(value interface{}) *C.zval { func convertGoToZval(value interface{}) *C.zval {
zval := (*C.zval)(C.__emalloc__(C.size_t(unsafe.Sizeof(C.zval{})))) var zval C.zval
u1 := (*C.uint8_t)(unsafe.Pointer(&zval.u1[0]))
v0 := unsafe.Pointer(&zval.value[0])
switch v := value.(type) { switch v := value.(type) {
case nil: case nil:
*u1 = C.IS_NULL C.__zval_null__(&zval)
case bool: case bool:
if v { C.__zval_bool__(&zval, C._Bool(v))
*u1 = C.IS_TRUE
} else {
*u1 = C.IS_FALSE
}
case int: case int:
*u1 = C.IS_LONG C.__zval_long__(&zval, C.zend_long(v))
*(*C.zend_long)(v0) = C.zend_long(v)
case int64: case int64:
*u1 = C.IS_LONG C.__zval_long__(&zval, C.zend_long(v))
*(*C.zend_long)(v0) = C.zend_long(v)
case float64: case float64:
*u1 = C.IS_DOUBLE C.__zval_double__(&zval, C.double(v))
*(*C.double)(v0) = C.double(v)
case string: case string:
*u1 = C.IS_STRING str := (*C.zend_string)(PHPString(v, false))
*(**C.zend_string)(v0) = (*C.zend_string)(PHPString(v, false)) C.__zval_string__(&zval, str)
case *Array: case *Array:
*u1 = C.IS_ARRAY arr := (*C.zend_array)(PHPArray(v))
*(**C.zend_array)(v0) = (*C.zend_array)(PHPArray(v)) C.__zval_arr__(&zval, arr)
default: default:
*u1 = C.IS_NULL C.__zval_null__(&zval)
} }
return zval return &zval
} }
// createNewArray creates a new zend_array with the specified size. // createNewArray creates a new zend_array with the specified size.
func createNewArray(size uint32) *C.HashTable { func createNewArray(size uint32) *C.HashTable {
ht := C.__emalloc__(C.size_t(unsafe.Sizeof(C.HashTable{}))) arr := C.__zend_new_array__(C.uint32_t(size))
C.__zend_hash_init__((*C.struct__zend_array)(ht), C.uint32_t(size), nil, C._Bool(false)) return (*C.HashTable)(unsafe.Pointer(arr))
return (*C.HashTable)(ht)
} }
// htIsPacked checks if a HashTable is a list (packed) or hashmap (not packed). // htIsPacked checks if a HashTable is a list (packed) or hashmap (not packed).

View File

@@ -14,4 +14,12 @@ void *__emalloc__(size_t size);
void __zend_hash_init__(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, void __zend_hash_init__(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor,
bool persistent); bool persistent);
void __zval_null__(zval *zv);
void __zval_bool__(zval *zv, bool val);
void __zval_long__(zval *zv, zend_long val);
void __zval_double__(zval *zv, double val);
void __zval_string__(zval *zv, zend_string *str);
void __zval_arr__(zval *zv, zend_array *arr);
zend_array *__zend_new_array__(uint32_t size);
#endif #endif