Skip to content

Commit af253a3

Browse files
committed
refactor and add tests
1 parent 256f037 commit af253a3

13 files changed

Lines changed: 633 additions & 124 deletions

Zend/zend_vm_def.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6806,8 +6806,7 @@ ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|CV, CONST|TMP|CV)
68066806
zval *offset;
68076807
zend_ulong hval;
68086808
zend_string *key;
6809-
bool should_flush_array = false;
6810-
bool should_publish_tracked_array = false;
6809+
bool should_flush_array = false, should_publish_tracked_array = false;
68116810

68126811
SAVE_OPLINE();
68136812
container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_UNSET);

Zend/zend_vm_execute.h

Lines changed: 12 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
--TEST--
2+
OPcache explicit volatile and pinned caches rebase shared graph direct arrays during relocation
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.enable=1
7+
opcache.enable_cli=1
8+
opcache.static_cache.volatile_size_mb=8
9+
opcache.static_cache.pinned_size_mb=8
10+
--FILE--
11+
<?php
12+
13+
class SharedGraphRelocationNode
14+
{
15+
public function __construct(
16+
public string $name,
17+
public array $rows,
18+
) {}
19+
}
20+
21+
function build_shared_graph_relocation_payload(string $label, int $multiplier): array
22+
{
23+
$rows = [];
24+
for ($i = 0; $i < 3000; $i++) {
25+
$rows[] = [
26+
'id' => $i,
27+
'text' => str_repeat($label, 48),
28+
'nested' => [$i * $multiplier, $i * $multiplier + 1],
29+
];
30+
}
31+
32+
return [
33+
'object' => new SharedGraphRelocationNode('node-' . $label, $rows),
34+
'plain' => [
35+
'label' => $label,
36+
'tail' => str_repeat($label, 256),
37+
],
38+
];
39+
}
40+
41+
function cache_clear_for_relocation(string $backend): void
42+
{
43+
$function = 'OPcache\\' . $backend . '_clear';
44+
$function();
45+
}
46+
47+
function cache_store_for_relocation(string $backend, string $key, mixed $value): bool
48+
{
49+
$function = 'OPcache\\' . $backend . '_store';
50+
51+
return $function($key, $value);
52+
}
53+
54+
function cache_fetch_for_relocation(string $backend, string $key): mixed
55+
{
56+
$function = 'OPcache\\' . $backend . '_fetch';
57+
58+
return $function($key);
59+
}
60+
61+
function cache_delete_for_relocation(string $backend, string $key): void
62+
{
63+
$function = 'OPcache\\' . $backend . '_delete';
64+
$function($key);
65+
}
66+
67+
function run_shared_graph_relocation(string $backend, string $label): void
68+
{
69+
echo "-- {$backend} --\n";
70+
71+
cache_clear_for_relocation($backend);
72+
73+
$prefix = $backend . '_shared_graph_relocation_';
74+
var_dump(cache_store_for_relocation($backend, $prefix . 'first', str_repeat('A', 1200000)));
75+
var_dump(cache_store_for_relocation($backend, $prefix . 'graph', build_shared_graph_relocation_payload($label, 5)));
76+
var_dump(cache_store_for_relocation($backend, $prefix . 'third', str_repeat('C', 1200000)));
77+
78+
cache_delete_for_relocation($backend, $prefix . 'first');
79+
80+
var_dump(cache_store_for_relocation($backend, $prefix . 'merged', str_repeat('M', 2400000)));
81+
82+
$graph = cache_fetch_for_relocation($backend, $prefix . 'graph');
83+
var_dump($graph['object'] instanceof SharedGraphRelocationNode);
84+
var_dump($graph['object']->name);
85+
var_dump($graph['object']->rows[123]['text']);
86+
var_dump($graph['object']->rows[123]['nested'][1]);
87+
var_dump($graph['plain']['label']);
88+
var_dump(strlen($graph['plain']['tail']));
89+
var_dump(strlen(cache_fetch_for_relocation($backend, $prefix . 'merged')));
90+
var_dump(strlen(cache_fetch_for_relocation($backend, $prefix . 'third')));
91+
}
92+
93+
run_shared_graph_relocation('volatile', 'V');
94+
run_shared_graph_relocation('pinned', 'P');
95+
96+
?>
97+
--EXPECT--
98+
-- volatile --
99+
bool(true)
100+
bool(true)
101+
bool(true)
102+
bool(true)
103+
bool(true)
104+
string(6) "node-V"
105+
string(48) "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV"
106+
int(616)
107+
string(1) "V"
108+
int(256)
109+
int(2400000)
110+
int(1200000)
111+
-- pinned --
112+
bool(true)
113+
bool(true)
114+
bool(true)
115+
bool(true)
116+
bool(true)
117+
string(6) "node-P"
118+
string(48) "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
119+
int(616)
120+
string(1) "P"
121+
int(256)
122+
int(2400000)
123+
int(1200000)
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
--TEST--
2+
OPcache pinned atomic operations warn and wrap on integer overflow
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.enable=1
7+
opcache.enable_cli=1
8+
opcache.static_cache.pinned_size_mb=32
9+
--FILE--
10+
<?php
11+
12+
function show_result(string $label, callable $callback, int $expected): void
13+
{
14+
echo "-- {$label} --\n";
15+
$result = $callback();
16+
echo "result: ";
17+
var_dump($result === $expected);
18+
}
19+
20+
OPcache\pinned_clear();
21+
22+
$maxKey = 'atomic_overflow_max_' . getmypid();
23+
$minKey = 'atomic_overflow_min_' . getmypid();
24+
$missingKey = 'atomic_overflow_missing_' . getmypid();
25+
$handlerProbeKey = 'atomic_overflow_handler_probe_' . getmypid();
26+
27+
OPcache\pinned_store($handlerProbeKey, 'ok');
28+
29+
set_error_handler(static function (int $severity, string $message) use ($handlerProbeKey): bool {
30+
echo "warning severity: ";
31+
var_dump($severity === E_WARNING);
32+
echo "warning message: {$message}\n";
33+
echo "handler fetch: ";
34+
var_dump(OPcache\pinned_fetch($handlerProbeKey) === 'ok');
35+
36+
return true;
37+
});
38+
39+
var_dump(OPcache\pinned_store($maxKey, PHP_INT_MAX));
40+
show_result('increment max no throw', static fn () => OPcache\pinned_atomic_increment($maxKey), PHP_INT_MIN);
41+
echo "max wrapped no throw: ";
42+
var_dump(OPcache\pinned_fetch($maxKey) === PHP_INT_MIN);
43+
44+
var_dump(OPcache\pinned_store($maxKey, PHP_INT_MAX));
45+
show_result('increment max throw flag', static fn () => OPcache\pinned_atomic_increment($maxKey, 1, true), PHP_INT_MIN);
46+
echo "max wrapped throw flag: ";
47+
var_dump(OPcache\pinned_fetch($maxKey) === PHP_INT_MIN);
48+
49+
var_dump(OPcache\pinned_store($minKey, PHP_INT_MIN));
50+
show_result('decrement min no throw', static fn () => OPcache\pinned_atomic_decrement($minKey), PHP_INT_MAX);
51+
echo "min wrapped no throw: ";
52+
var_dump(OPcache\pinned_fetch($minKey) === PHP_INT_MAX);
53+
54+
var_dump(OPcache\pinned_store($minKey, PHP_INT_MIN));
55+
show_result('decrement min throw flag', static fn () => OPcache\pinned_atomic_decrement($minKey, 1, true), PHP_INT_MAX);
56+
echo "min wrapped throw flag: ";
57+
var_dump(OPcache\pinned_fetch($minKey) === PHP_INT_MAX);
58+
59+
show_result('decrement missing min step', static fn () => OPcache\pinned_atomic_decrement($missingKey, PHP_INT_MIN), PHP_INT_MIN);
60+
echo "missing wrapped: ";
61+
var_dump(OPcache\pinned_fetch($missingKey) === PHP_INT_MIN);
62+
63+
?>
64+
--EXPECT--
65+
bool(true)
66+
-- increment max no throw --
67+
warning severity: bool(true)
68+
warning message: OPcache\pinned_atomic_increment(): Integer overflow occurred; result wrapped around
69+
handler fetch: bool(true)
70+
result: bool(true)
71+
max wrapped no throw: bool(true)
72+
bool(true)
73+
-- increment max throw flag --
74+
warning severity: bool(true)
75+
warning message: OPcache\pinned_atomic_increment(): Integer overflow occurred; result wrapped around
76+
handler fetch: bool(true)
77+
result: bool(true)
78+
max wrapped throw flag: bool(true)
79+
bool(true)
80+
-- decrement min no throw --
81+
warning severity: bool(true)
82+
warning message: OPcache\pinned_atomic_decrement(): Integer overflow occurred; result wrapped around
83+
handler fetch: bool(true)
84+
result: bool(true)
85+
min wrapped no throw: bool(true)
86+
bool(true)
87+
-- decrement min throw flag --
88+
warning severity: bool(true)
89+
warning message: OPcache\pinned_atomic_decrement(): Integer overflow occurred; result wrapped around
90+
handler fetch: bool(true)
91+
result: bool(true)
92+
min wrapped throw flag: bool(true)
93+
-- decrement missing min step --
94+
warning severity: bool(true)
95+
warning message: OPcache\pinned_atomic_decrement(): Integer overflow occurred; result wrapped around
96+
handler fetch: bool(true)
97+
result: bool(true)
98+
missing wrapped: bool(true)

0 commit comments

Comments
 (0)