Skip to content

Commit a18df90

Browse files
committed
Fix phpGH-13817: Segmentation fault for enabled observers after pass 4
Instead of fixing up temporaries count in between observer steps, just apply the additional temporary in the two affected observer steps. Closes phpGH-14018.
1 parent fdcfd62 commit a18df90

File tree

5 files changed

+59
-15
lines changed

5 files changed

+59
-15
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ PHP NEWS
1717
. Fixed bug GH-14286 (ffi enum type (when enum has no name) make memory
1818
leak). (nielsdos, dstogov)
1919

20+
- Opcache:
21+
. Fixed bug GH-13817 (Segmentation fault for enabled observers after pass 4).
22+
(Bob)
23+
2024
- Soap:
2125
. Fixed bug #55639 (Digest autentication dont work). (nielsdos)
2226

Zend/Optimizer/compact_vars.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "Optimizer/zend_optimizer_internal.h"
2020
#include "zend_bitset.h"
21+
#include "zend_observer.h"
2122

2223
/* This pass removes all CVs and temporaries that are completely unused. It does *not* merge any CVs or TMPs.
2324
* This pass does not operate on SSA form anymore. */
@@ -117,7 +118,7 @@ void zend_optimizer_compact_vars(zend_op_array *op_array) {
117118
op_array->last_var = num_cvs;
118119
}
119120

120-
op_array->T = num_tmps;
121+
op_array->T = num_tmps + ZEND_OBSERVER_ENABLED; // reserve last temporary for observers if enabled
121122

122123
free_alloca(vars_map, use_heap2);
123124
}

Zend/Optimizer/optimize_temp_vars_5.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "zend_execute.h"
2727
#include "zend_vm.h"
2828
#include "zend_bitset.h"
29+
#include "zend_observer.h"
2930

3031
#define INVALID_VAR ((uint32_t)-1)
3132
#define GET_AVAILABLE_T() \
@@ -173,5 +174,5 @@ void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_c
173174
}
174175

175176
zend_arena_release(&ctx->arena, checkpoint);
176-
op_array->T = max + 1;
177+
op_array->T = max + 1 + ZEND_OBSERVER_ENABLED; // reserve last temporary for observers if enabled
177178
}

Zend/Optimizer/zend_optimizer.c

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
#include "zend_inference.h"
3232
#include "zend_dump.h"
3333
#include "php.h"
34-
#include "zend_observer.h"
3534

3635
#ifndef ZEND_OPTIMIZER_MAX_REGISTERED_PASSES
3736
# define ZEND_OPTIMIZER_MAX_REGISTERED_PASSES 32
@@ -1097,8 +1096,6 @@ static void zend_revert_pass_two(zend_op_array *op_array)
10971096
}
10981097
#endif
10991098

1100-
op_array->T -= ZEND_OBSERVER_ENABLED;
1101-
11021099
op_array->fn_flags &= ~ZEND_ACC_DONE_PASS_TWO;
11031100
}
11041101

@@ -1128,8 +1125,6 @@ static void zend_redo_pass_two(zend_op_array *op_array)
11281125
}
11291126
#endif
11301127

1131-
op_array->T += ZEND_OBSERVER_ENABLED; // reserve last temporary for observers if enabled
1132-
11331128
opline = op_array->opcodes;
11341129
end = opline + op_array->last;
11351130
while (opline < end) {
@@ -1557,12 +1552,6 @@ ZEND_API void zend_optimize_script(zend_script *script, zend_long optimization_l
15571552
}
15581553
}
15591554

1560-
if (ZEND_OBSERVER_ENABLED) {
1561-
for (i = 0; i < call_graph.op_arrays_count; i++) {
1562-
++call_graph.op_arrays[i]->T; // ensure accurate temporary count for stack size precalculation
1563-
}
1564-
}
1565-
15661555
if (ZEND_OPTIMIZER_PASS_12 & optimization_level) {
15671556
for (i = 0; i < call_graph.op_arrays_count; i++) {
15681557
zend_adjust_fcall_stack_size_graph(call_graph.op_arrays[i]);
@@ -1578,8 +1567,6 @@ ZEND_API void zend_optimize_script(zend_script *script, zend_long optimization_l
15781567
zend_recalc_live_ranges(op_array, needs_live_range);
15791568
}
15801569
} else {
1581-
op_array->T -= ZEND_OBSERVER_ENABLED; // redo_pass_two will re-increment it
1582-
15831570
zend_redo_pass_two(op_array);
15841571
if (op_array->live_range) {
15851572
zend_recalc_live_ranges(op_array, NULL);

ext/opcache/tests/gh13817.phpt

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--TEST--
2+
GH-13712 (Segmentation fault for enabled observers after pass 4)
3+
--EXTENSIONS--
4+
opcache
5+
zend_test
6+
--INI--
7+
zend_test.observer.enabled=1
8+
zend_test.observer.show_output=1
9+
zend_test.observer.observe_all=1
10+
opcache.enable=1
11+
opcache.enable_cli=1
12+
opcache.optimization_level=0x4069
13+
--FILE--
14+
<?php
15+
16+
function inner() {
17+
echo "Ok\n";
18+
}
19+
20+
function foo() {
21+
// If stack size is wrong, inner() will corrupt the previous observed frame
22+
inner();
23+
}
24+
25+
// After foo() def so that we land here, with step_two undone for foo() first
26+
function outer() {
27+
// Pass 15 does constant string propagation, which gives a ZEND_INIT_DYNAMIC_FCALL on a const which Pass 4 will optimize
28+
// Pass 4 must calc the right stack size here
29+
(NAME)();
30+
}
31+
32+
const NAME = "foo";
33+
34+
outer();
35+
36+
?>
37+
--EXPECTF--
38+
<!-- init '%s' -->
39+
<file '%s'>
40+
<!-- init outer() -->
41+
<outer>
42+
<!-- init foo() -->
43+
<foo>
44+
<!-- init inner() -->
45+
<inner>
46+
Ok
47+
</inner>
48+
</foo>
49+
</outer>
50+
</file '%s'>
51+

0 commit comments

Comments
 (0)