Search code examples
phpzend-frameworkphp-extensionphp-7

PHP 7 return dynamic alloc zval right way


what is actually the right way to return a dynamic allocated zval from a c function, and register it's automatic dtor?

zval * php_test_fcn() {
    zval * t;
    t = ecalloc(sizeof(zval), 1);
    ZVAL_LONG(t, 1);
    return t;
}

And on the other side I call:

zval **params = NULL;
int arg_num=5;
int x=0;
params = ecalloc(arg_num, sizeof(zval));
for(x=0; x<arg_num; x++) {
    params[i]=php_test_fcn();
}

///SOME MORE code
/// call_user_function .....
call_user_function(EG(function_table), NULL, func, &return_value, arg_num, *params TSRMLS_CC);
//cleanup
for(x=0; x<arg_num; x++) {
    zval_ptr_dtor(params[i]);
}
efree(params);     

Before PHP 7 I used: MAKE_STD_ZVAL() which seemed to register an auto-dtor. right now valgrind shows that the ecalloc from php_test_fcn() leaks.

Any advice?

p.s.: the code is extracted from a project, and maybe not 100% right - i tried to minify it.

UPDATE:

The ecalloc on params - is the actual leak.

If I do it:

zval params[100];
int  i      = 0;
int  arg_num  = lua_gettop(L);

//params = ecalloc(arg_num, sizeof(zval));
if(arg_num >= 100) return 0;

for (i=0; i<arg_num; i++) {     
    //params[i] = php_lua_get_zval_from_lua(L, -(arg_num-i), NULL TSRMLS_CC);
    ZVAL_COPY_VALUE(&params[i], php_lua_get_zval_from_lua(L, -(arg_num-i), NULL TSRMLS_CC));

}

call_user_function(EG(function_table), NULL, func, &return_value, arg_num, params TSRMLS_CC);
php_lua_send_zval_to_lua(L, &return_value TSRMLS_CC);

for (i=0; i<arg_num; i++) {
    zval_ptr_dtor(&params[i]);
}

//efree(params);
zval_ptr_dtor(&return_value);

It doesn't leak - coz of local variables. any idea whats wrong with the ecalloc on the ** pointer?


Solution

  • ok answered it to myself :D

    problem was the **pointer.

    Final code - did it:

    zval * params = NULL;
    zval * t;
    int  i      = 0;
    int  arg_num  = lua_gettop(L);
    
    params = safe_emalloc(sizeof(zval), arg_num, 0);
    //if(arg_num >= 100) return 0;
    
    for (i=0; i<arg_num; i++) {
        //params[i]=ecalloc(1, sizeof(zval));
        //params[i] = php_lua_get_zval_from_lua(L, -(arg_num-i), NULL TSRMLS_CC);
        params[i]=*php_lua_get_zval_from_lua(L, -(arg_num-i), NULL TSRMLS_CC);                      
    }
    
    
    call_user_function(EG(function_table), NULL, func, &return_value, arg_num, params TSRMLS_CC);
    php_lua_send_zval_to_lua(L, &return_value TSRMLS_CC);
    
    for (i=0; i<arg_num; i++) {
        zval_ptr_dtor(&params[i]);
        //efree(params[i]);
    }
    
    efree(params);
    zval_ptr_dtor(&return_value);