Search code examples
phpcvalgrindphp-extension

call_user_function makes memory leak


I have a simple PHP extension method

PHP_METHOD(NaviModel, addRules) {
    zval *ruleParam, *rules, function, rv, args[2];

    ZEND_PARSE_PARAMETERS_START(1, 1)
        Z_PARAM_ZVAL(ruleParam)
    ZEND_PARSE_PARAMETERS_END();

    rules = zend_read_property(naviModelCe, Z_OBJ_P(ZEND_THIS), ZEND_STRL("rules"), ZEND_FETCH_CLASS_SILENT, &rv);

    ZVAL_STRING(&function, "array_replace_recursive");
    args[0] = *ruleParam;
    args[1] = *rules;

    call_user_function(NULL, NULL, &function, rules, 2, args);

    zval_ptr_dtor(ruleParam);
    zval_ptr_dtor(&function);
    zval_dtor(args);
}

When I run test with the valgrind, it show several errors, start with Invalid read of size 4

==52047== Invalid read of size 4
==52047==    at 0x708994: zend_gc_addref (zend_types.h:1161)
==52047==    by 0x70C02F: zend_call_function (zend_execute_API.c:798)
==52047==    by 0x70B983: _call_user_function_impl (zend_execute_API.c:659)
==52047==    by 0x72A4707: zim_NaviModel_addRules (model.c:98)
==52047==    by 0x76651B: ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1755)
==52047==    by 0x7E8E9F: execute_ex (zend_vm_execute.h:55172)
==52047==    by 0x7ED5A7: zend_execute (zend_vm_execute.h:59499)
==52047==    by 0x725AAB: zend_execute_scripts (zend.c:1694)
==52047==    by 0x676877: php_execute_script (main.c:2543)
==52047==    by 0x833443: do_cli (php_cli.c:949)
==52047==    by 0x8342E7: main (php_cli.c:1337)
==52047==  Address 0x715b380 is 0 bytes inside a block of size 56 free'd
==52047==    at 0x4851A40: free (in /usr/libexec/valgrind/vgpreload_memcheck-arm64-linux.so)
==52047==    by 0x6E651B: _efree_custom (zend_alloc.c:2427)
==52047==    by 0x6E669B: _efree (zend_alloc.c:2547)
==52047==    by 0x73F673: zend_array_destroy (zend_hash.c:1662)
==52047==    by 0x720FC7: rc_dtor_func (zend_variables.c:57)
==52047==    by 0x720F3F: i_zval_ptr_dtor (zend_variables.h:44)
==52047==    by 0x72117B: zval_ptr_dtor (zend_variables.c:84)
==52047==    by 0x72B02D3: naviModelNewsRules (news.c:35)
==52047==    by 0x72B09FF: zim_NaviModelNews___construct (news.c:104)
==52047==    by 0x76651B: ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1755)
==52047==    by 0x7E8E9F: execute_ex (zend_vm_execute.h:55172)
==52047==    by 0x7ED5A7: zend_execute (zend_vm_execute.h:59499)

The model.c:98 is the line call_user_function(NULL, NULL, &function, rules, 2, args); Can you help to point out the problem?


Solution

  • zval retval;
    call_user_function(NULL, NULL, &function, &retval, 2, args);
    

    Zend will clean the return value before calling the function, but the return value and the second parameter are pointed to the same address, that is the problem.