> -----Original Message-----
> From: Hollenbeck, Scott [mailto:[email protected]]
> Sent: Sunday, April 26, 2015 6:35 PM
> To: [email protected]
> Subject: [PECL-DEV] SIGSEGV When Calling call_user_function()
> 
> I've run into a segmentation fault situation when calling
> call_user_function() in an extension I'm developing. I can reproduce
> the fault reliably when trying to pass 4 arguments to my user function.
> The strange (to me anyway) thing is that it doesn't crash when passing
> 3 or fewer arguments. Can anyone point out what might be causing this
> error? Here's my source code:
> 
> void async_callback(getdns_context *context,
>                   getdns_callback_type_t callbackType,
>                   getdns_dict *response,
>                   void *userArg, getdns_transaction_t transID)
> {
>     int phpResult = 0;
>     zval *userArgs, **hashData;
>     zval *clientArgs[4];
>     zval cbType, dictVal, funcName, retVal, transIDVal;
>     char *phpCallback = NULL;
>     HashTable *arrayHash;
>     HashPosition hashPtr;
> 
>     userArgs = (zval *) userArg;
>     arrayHash = Z_ARRVAL_P(userArgs);
>     zend_hash_internal_pointer_reset_ex(arrayHash, &hashPtr);
>     if (zend_hash_get_current_data_ex(arrayHash, (void**) &hashData,
> &hashPtr) == SUCCESS) {
>         phpCallback = (char *) Z_STRVAL_PP(hashData);
>     }
>     else {
>         php_error_docref(NULL TSRMLS_DC, E_ERROR, "Invalid callback
> parameters!");
>       return;
>     }
> 
>     ZVAL_STRING(&funcName, phpCallback, 0);
> 
>     clientArgs[0] = &dictVal;
>     ZVAL_LONG(clientArgs[0], (long) response);
> 
>     clientArgs[1] = &cbType;
>     ZVAL_LONG(clientArgs[1], (long) callbackType);
> 
>     clientArgs[2] = userArgs;
> 
>     clientArgs[3] = &transIDVal;
>     ZVAL_STRING(clientArgs[3], "0000000000000000", 1);
> 
>     phpResult = call_user_function(EG(function_table), NULL,
>                    &funcName, &retVal, 4, clientArgs TSRMLS_DC);
>     if (phpResult == FAILURE) {
>         php_error_docref(NULL TSRMLS_DC, E_ERROR, "Callback failed!");
>     }
> }

I did a little more reading through Sara Golemon's "Extending and Embedding 
PHP" book and with some more experimentation I got this to work without 
crashing. Here's the code that works (comments stripped):

void async_callback(getdns_context *context,
                    getdns_callback_type_t callbackType,
                    getdns_dict *response,
                    void *userArg,
                    getdns_transaction_t transID)
{
    int phpResult = 0;
    zval *clientArgs[4], *userArgs, **hashData;
    zval funcName, retVal;
    char *phpCallback = NULL;
    HashTable *arrayHash;
    HashPosition hashPtr;

    userArgs = (zval *) userArg;
    arrayHash = Z_ARRVAL_P(userArgs);
    zend_hash_internal_pointer_reset_ex(arrayHash, &hashPtr);
    if (zend_hash_get_current_data_ex(arrayHash, (void**) &hashData, &hashPtr) 
== SUCCESS) {
        phpCallback = (char *) Z_STRVAL_PP(hashData);
    }
    else {
        php_error_docref(NULL TSRMLS_DC, E_ERROR, "Invalid callback 
parameters!");
           return;
    }

    ZVAL_STRING(&funcName, phpCallback, 1);
    MAKE_STD_ZVAL(clientArgs[0]);
    ZVAL_LONG(clientArgs[0], (long) response);
    MAKE_STD_ZVAL(clientArgs[1]);
    ZVAL_LONG(clientArgs[1], callbackType);
    MAKE_STD_ZVAL(clientArgs[2]);
    clientArgs[2] = userArgs;
    MAKE_STD_ZVAL(clientArgs[3]);
    ZVAL_STRING(clientArgs[3], "0000000000000000", 1);

    phpResult = call_user_function(EG(function_table), NULL,
                   &funcName, &retVal, 4, clientArgs TSRMLS_DC);
    if (phpResult == FAILURE) {
        php_error_docref(NULL TSRMLS_DC, E_ERROR, "Callback failed!");
    }

    zval_dtor(&funcName);
    zval_dtor(clientArgs[0]);
    zval_dtor(clientArgs[1]);
    zval_dtor(clientArgs[3]);
}

Being explicit about allocating and freeing the parameter zvals seems to have 
made the difference.

Scott

--
PECL development discussion Mailing List (http://pecl.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to