Skip to content

Commit 4002ffb

Browse files
committed
Require types to be available for preloading
1 parent 750bbe7 commit 4002ffb

File tree

4 files changed

+115
-0
lines changed

4 files changed

+115
-0
lines changed

ext/opcache/ZendAccelerator.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3398,6 +3398,44 @@ static zend_bool preload_try_resolve_property_types(zend_class_entry *ce)
33983398
return ok;
33993399
}
34003400

3401+
static zend_bool preload_is_type_known(zend_class_entry *ce, zend_type type) {
3402+
zend_string *name, *lcname;
3403+
zend_bool known;
3404+
if (!ZEND_TYPE_IS_NAME(type)) {
3405+
return 1;
3406+
}
3407+
3408+
name = ZEND_TYPE_NAME(type);
3409+
if (zend_string_equals_literal_ci(name, "self") ||
3410+
zend_string_equals_literal_ci(name, "parent") ||
3411+
zend_string_equals_ci(name, ce->name)) {
3412+
return 1;
3413+
}
3414+
3415+
lcname = zend_string_tolower(name);
3416+
known = zend_hash_exists(EG(class_table), lcname);
3417+
zend_string_release(lcname);
3418+
return known;
3419+
}
3420+
3421+
static zend_bool preload_all_types_known(zend_class_entry *ce) {
3422+
zend_function *fptr;
3423+
ZEND_HASH_FOREACH_PTR(&ce->function_table, fptr) {
3424+
uint32_t i;
3425+
if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
3426+
if (!preload_is_type_known(ce, fptr->common.arg_info[-1].type)) {
3427+
return 0;
3428+
}
3429+
}
3430+
for (i = 0; i < fptr->common.num_args; i++) {
3431+
if (!preload_is_type_known(ce, fptr->common.arg_info[i].type)) {
3432+
return 0;
3433+
}
3434+
}
3435+
} ZEND_HASH_FOREACH_END();
3436+
return 1;
3437+
}
3438+
34013439
static void preload_link(void)
34023440
{
34033441
zval *zv;
@@ -3491,6 +3529,10 @@ static void preload_link(void)
34913529
if (!found) continue;
34923530
}
34933531

3532+
if (!preload_all_types_known(ce)) {
3533+
continue;
3534+
}
3535+
34943536
zend_string *key = zend_string_tolower(ce->name);
34953537
zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, key);
34963538
zend_string_release(key);

ext/opcache/tests/preload_011.phpt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
Argument/return types must be available for preloading
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.optimization_level=-1
7+
opcache.preload={PWD}/preload_variance_ind.inc
8+
--SKIPIF--
9+
<?php require_once('skipif.inc'); ?>
10+
--FILE--
11+
<?php
12+
interface K {}
13+
interface L extends K {}
14+
require __DIR__ . '/preload_variance.inc';
15+
16+
$a = new A;
17+
$b = new B;
18+
$d = new D;
19+
$f = new F;
20+
$g = new G;
21+
22+
?>
23+
===DONE===
24+
--EXPECTF--
25+
Warning: Can't preload unlinked class H in %s on line %d
26+
27+
Warning: Can't preload unlinked class B in %s on line %d
28+
29+
Warning: Can't preload unlinked class A in %s on line %d
30+
===DONE===
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
// Requires X, delay to runtime.
4+
// TODO: It is not actually required, because we don't need X to check inheritance in this case.
5+
class A extends Z {
6+
public function method(X $a) {}
7+
}
8+
class B extends Z {
9+
public function method($a) : X {}
10+
}
11+
12+
// Works.
13+
class C extends Z {
14+
public function method($a): self {}
15+
public function method2($a): C {}
16+
}
17+
class D extends C {
18+
public function method($a): self {}
19+
public function method2($a): D {}
20+
}
21+
22+
// Works.
23+
interface I {}
24+
interface J extends I {}
25+
class E {
26+
public function method($a): I {}
27+
}
28+
class F extends E {
29+
public function method($a): J {}
30+
}
31+
32+
// Requires K & L, delay to runtime.
33+
class G {
34+
public function method($a): K {}
35+
}
36+
class H extends G {
37+
public function method($a): L {}
38+
}
39+
40+
// Early-binding preventer.
41+
class Z {}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?php
2+
opcache_compile_file(__DIR__ . '/preload_variance.inc');

0 commit comments

Comments
 (0)