> -----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