Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does PHP 7 remove the resources from the regular list?

I am upgrading a php extension to php 7, and I want to remove a resource that is been registered in the regular list using zend_register_resourceand later I am closing the resource using zend_list_close. the closing function looks like this:

    PHP_FUNCTION(myFunc_cleanAndExit)
    {
     zval* rsrc = NULL;
     ...
     int res = zend_parse_parameters(ZEND_NUM_ARGS() , "r", &rsrc );
     if (res == FAILURE)
     {
        //handle it
     }
     ...
     zend_fetch_resource(Z_RES_P(rsrc), ./other args/..)
     ...
     zend_list_close(Z_RES_P(rsrc));
     ...
     }

originally in PHP 5, rsrc is removed using zend_hash_index_del( &EG( regular_list ), Z_RESVAL_P( rsrc)), so if this function is called twice, zend_parse_parameter returns FAILURE, because the resource is removed from the regular list and doesn't exist.

In PHP7, zend_list_close calls zend_resource_dtor (rsrc refcount is 2(why is is incremented? after registering resource it was 1)) and cleans any memory that rsrc is holding up. But, the fun happens when we call it twice like this:

    myFunc_cleanAndExit($var-rsrc);
    myFunc_cleanAndExit($var-rsrc);

the second time zend_parse_parameter doesn't return FAILURE(cause the resource hasn't been removed from the regular list), and the refcount of the rsrc is incremented to 3 after parsing it, the type is -1 and ptr is NULL(assigned in zend_resource_dtor in the first call). When I call get_resources() in PHP script, I get the rsrc with its id and the type UNKOWN, which in PHP5 rsrc becomes NULL. Here are my questions:

1- when are the resources removed from regular list? (if I manually remove it from regular list using zend_hash_index_del, it breaks in the zend_alloc)

2- Is this Ok to have the resource active with type UNKOWN after closing it once? doesn't eat up the memory? If not, what should I do to have it as NULL?

3- When I register the resource, and check its refcount, it is 1, but when I call the closing function, after zend_parse_parameter the refcount gets incremented, why?

Thanks

sample PHP script:

    <?php
    $var_rsrc = myFunc_startUp();
    var_dump($var_rsrc); // resource(2) of type 'MyFunc'
    myFunc_cleanAndExit($var_rsrc);
    var_dump($var_rsrc); // resource(2) of type 'UNKOWN' (originally this was  NULL)
    myFunc_cleanAndExit($var_rsrc);
    var_dump($var_rsrc); // resource(2) of type 'UNKOWN'
like image 403
Genjutsu Avatar asked Mar 17 '26 15:03

Genjutsu


1 Answers

The short answer is that the resource gets removed at request shutdown, specifically in zend_hash_graceful_reverse_destroy. You should also check the return value of zend_fetch_resource because it will return NULL (and emit a warning) for a destructed resource.

I think everything you're describing is normal, including zend_parse_parameters succeeding to parse a previously destructed resource. The program below exhibits the exact same behavior:

<?php
$r = popen('ls', 'r');
echo fgets($r);
pclose($r);
var_dump(get_resources());
pclose($r);

The refcount of your resource is 2 because the SEND_VAR opcode (i.e., passing a param to a function) will ZVAL_COPY it to the arglist, which increments the refcount. (It is later deref'd in zend_vm_stack_free_args.)

Regarding memory usage, I wouldn't worry about the resource eating up memory. We already know it doesn't leak as it gets cleaned up at RSHUTDOWN. And even if you were to manually remove the item from the hash, I don't think the underlying memory is guaranteed to be deallocated immediately.

like image 107
adsr Avatar answered Mar 20 '26 09:03

adsr



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!