]> granicus.if.org Git - php/commitdiff
Intern alias old_name early
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 12 Aug 2019 14:58:52 +0000 (16:58 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 12 Aug 2019 15:12:28 +0000 (17:12 +0200)
This is likely going to end up interned lateron at some point
when the new_name is referenced somewhere. However, it may be
that there are some uses that do not get interned before that.
In this case we will intern a string that already have zval
users, without updating the refcounted flag on those zvals.

In particular this can happen with something like [Foo::class],
where Foo is an imported symbol. The string it resolves to won't
get interned right away, but may be interned later.

    use Foo as Bar;
    $x = [Bar::class];
    var_dump(Bar::X);
    debug_zval_dump($x); // Will show negative refcount
    class Foo {
        const X = 1;
    }

However, this doesn't really fix the root cause, there are probably
other situations where something similar can occur.

Zend/zend_compile.c

index a91dfeeecfea9f8f2c878d3092e2c23d8a4203c9..f25ce2f55d809456bec520ec128679d2e1122567 100644 (file)
@@ -6619,6 +6619,7 @@ void zend_compile_use(zend_ast *ast) /* {{{ */
                }
 
                zend_string_addref(old_name);
+               old_name = zend_new_interned_string(old_name);
                if (!zend_hash_add_ptr(current_import, lookup_name, old_name)) {
                        zend_error_noreturn(E_COMPILE_ERROR, "Cannot use%s %s as %s because the name "
                                "is already in use", zend_get_use_type_str(type), ZSTR_VAL(old_name), ZSTR_VAL(new_name));