RE: SIGSEGV When Calling call_user_function()

From: Date: Mon, 27 Apr 2015 17:19:45 +0000
Subject: RE: SIGSEGV When Calling call_user_function()
References: 1  Groups: php.pecl.dev 
Request: Send a blank email to pecl-dev+get-12865@lists.php.net to get a copy of this message
> -----Original Message----- > From: Hollenbeck, Scott [mailto:shollenbeck@verisign.com] > Sent: Sunday, April 26, 2015 6:35 PM > To: pecl-dev@lists.php.net > 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

« previous php.pecl.dev (#12865) next »