简体   繁体   中英

Seg fault in extension after calling PHP function from C

I am trying to write an extension that calls back a PHP function after doing stuff. To check feasibility, I went as per this article: https://devzone.zend.com/303/extension-writing-part-i-introduction-to-php-and-zend/

The basic extension worked fine. Then I added code to call PHP function like this:

PHP_FUNCTION(hello_world)
{
    zval p1;
    INIT_ZVAL(p1);
    ZVAL_STRING(&p1, "From extension", 1);
    zval *params = { &p1 };
    zend_uint param_count = 1;
    zval *retval_ptr = NULL;

    zval function_name;
    INIT_ZVAL(function_name);
    ZVAL_STRING(&function_name, "from_ext", 1);

    if (call_user_function(
            CG(function_table), NULL /* no object */, &function_name,
            retval_ptr, param_count, &params TSRMLS_CC
        ) == SUCCESS
    ) {
        printf("Success returning from PHP");
        if (retval_ptr)
          zval_ptr_dtor(&retval_ptr);
    }

    /* don't forget to free the zvals */
    zval_dtor(&function_name);
    zval_dtor(&p1);

    RETURN_STRING("Hello World", 1);
}

and the calling PHP:

<?
function from_ext($arg) {
  echo "In PHP:", $arg;
  return "hello";
}

echo hello_world();

?>

It does call the PHP function and can see the value, but throws a Seg fault after that:

php -dextension=modules/hello.so test.php
In PHP:From extensionSegmentation fault: 11

I am trying on MacOS 10.12.6 with PHP that came with it (5.6.30).

Any idea how to overcome the Seg fault?

You need to allocate the return value zval on the stack. The pointer passed into call_user_function must be non-NULL. Here's a patch that should fix the issue.

--- a/mnt/tmpdisk/a.c
+++ b/mnt/tmpdisk/b.c
@@ -5,7 +5,7 @@ PHP_FUNCTION(hello_world)
     ZVAL_STRING(&p1, "From extension", 1);
     zval *params = { &p1 };
     zend_uint param_count = 1;
-    zval *retval_ptr = NULL;
+    zval retval;

     zval function_name;
     INIT_ZVAL(function_name);
@@ -13,12 +13,11 @@ PHP_FUNCTION(hello_world)

     if (call_user_function(
             CG(function_table), NULL /* no object */, &function_name,
-            retval_ptr, param_count, &params TSRMLS_CC
+            &retval, param_count, &params TSRMLS_CC
         ) == SUCCESS
     ) {
         printf("Success returning from PHP");
-        if (retval_ptr)
-          zval_ptr_dtor(&retval_ptr);
+        zval_dtor(&retval);
     }

     /* don't forget to free the zvals */

It's perfectly fine to pass in a pointer to stack-allocated memory since the PHP engine will never capture a reference to the return value zval anywhere in the call (since the return value is unnamed in userspace).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM