Skip to content

Commit 359ad80

Browse files
committed
Fix race condition in zend_runtime_jit(), zend_jit_hot_func()
zend_runtime_jit() prevents concurrent compilation with zend_shared_alloc_lock(), but this doesn't prevent blocked threads from trying to compile the function again after they acquire the lock. In the case of phpGH-19889, one of the function entries is compiled with zend_jit_handler(), which fails when the op handler has already been replaced by a JIT'ed handler. Fix by marking compiled functions with a new flag ZEND_FUNC_JITED, and skipping compilation of marked functions. The same fix is applied to zend_jit_hot_func(). Fixes phpGH-19889 Closes phpGH-19971
1 parent 08924cd commit 359ad80

File tree

3 files changed

+11
-5
lines changed

3 files changed

+11
-5
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ PHP NEWS
4444
. Fixed bug GH-19669 (assertion failure in zend_jit_trace_type_to_info_ex).
4545
(Arnaud)
4646
. Fixed bug GH-19831 (function JIT may not deref property value). (Arnaud)
47+
. Fixed bug GH-19889 (race condition in zend_runtime_jit(),
48+
zend_jit_hot_func()). (Arnaud)
4749

4850
- Phar:
4951
. Fix memory leak and invalid continuation after tar header writing fails.

Zend/Optimizer/zend_func_info.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
#define ZEND_FUNC_JIT_ON_PROF_REQUEST (1<<14) /* used by JIT */
4040
#define ZEND_FUNC_JIT_ON_HOT_COUNTERS (1<<15) /* used by JIT */
4141
#define ZEND_FUNC_JIT_ON_HOT_TRACE (1<<16) /* used by JIT */
42-
42+
#define ZEND_FUNC_JITED (1<<17) /* used by JIT */
4343

4444
typedef struct _zend_func_info zend_func_info;
4545
typedef struct _zend_call_info zend_call_info;

ext/opcache/jit/zend_jit.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2945,8 +2945,9 @@ static int ZEND_FASTCALL zend_runtime_jit(void)
29452945
bool do_bailout = 0;
29462946

29472947
zend_shared_alloc_lock();
2948+
jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
29482949

2949-
if (ZEND_FUNC_INFO(op_array)) {
2950+
if (jit_extension && !(jit_extension->func_info.flags & ZEND_FUNC_JITED)) {
29502951

29512952
SHM_UNPROTECT();
29522953
zend_jit_unprotect();
@@ -2958,11 +2959,12 @@ static int ZEND_FASTCALL zend_runtime_jit(void)
29582959
opline++;
29592960
}
29602961
}
2961-
jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
2962-
opline->handler = jit_extension->orig_handler;
2962+
((zend_op*)opline)->handler = jit_extension->orig_handler;
29632963

29642964
/* perform real JIT for this function */
29652965
zend_real_jit_func(op_array, NULL, NULL, ZEND_JIT_ON_FIRST_EXEC);
2966+
2967+
jit_extension->func_info.flags |= ZEND_FUNC_JITED;
29662968
} zend_catch {
29672969
do_bailout = true;
29682970
} zend_end_try();
@@ -3024,7 +3026,7 @@ void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend
30243026
zend_shared_alloc_lock();
30253027
jit_extension = (zend_jit_op_array_hot_extension*)ZEND_FUNC_INFO(op_array);
30263028

3027-
if (jit_extension) {
3029+
if (jit_extension && !(jit_extension->func_info.flags & ZEND_FUNC_JITED)) {
30283030
SHM_UNPROTECT();
30293031
zend_jit_unprotect();
30303032

@@ -3039,6 +3041,8 @@ void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend
30393041

30403042
/* perform real JIT for this function */
30413043
zend_real_jit_func(op_array, NULL, opline, ZEND_JIT_ON_HOT_COUNTERS);
3044+
3045+
jit_extension->func_info.flags |= ZEND_FUNC_JITED;
30423046
} zend_catch {
30433047
do_bailout = 1;
30443048
} zend_end_try();

0 commit comments

Comments
 (0)