Commit 8588ad453fc for php
commit 8588ad453fc4dba1b1b8e3bda7ca783cea8e21f6
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Sun Nov 8 19:30:20 2026 -0500
ext/opcache: Fix JIT code emitted past the buffer end on 32-bit
ir_emit_code() and ir_emit_exitgroup() round code_buffer->pos up to 16
bytes before checking the remaining space. On 32-bit builds the JIT buffer
end is only 8-byte aligned, so a pos in the last 8 bytes yields an entry
past the end, the unsigned size check wraps, and the code is encoded out of
bounds. ext/opcache/tests/jit/gh25165.phpt crashes this way on the nightly
x86 lanes. Reject an aligned entry beyond the end; the aarch64 emitters get
the same guard.
Closes GH-25331
diff --git a/ext/opcache/jit/ir/ir_aarch64.dasc b/ext/opcache/jit/ir/ir_aarch64.dasc
index c3e88e46e3b..28a0efb5ca6 100644
--- a/ext/opcache/jit/ir/ir_aarch64.dasc
+++ b/ext/opcache/jit/ir/ir_aarch64.dasc
@@ -6914,7 +6914,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
if (ctx->code_buffer) {
entry = ctx->code_buffer->pos;
entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 16);
- if (size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
+ if ((char*)entry > (char*)ctx->code_buffer->end || size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
dasm_free(&data.dasm_state);
ctx->data = NULL;
ctx->status = IR_ERROR_CODE_MEM_OVERFLOW;
@@ -7057,7 +7057,7 @@ const void *ir_emit_exitgroup(uint32_t first_exit_point, uint32_t exit_points_pe
entry = code_buffer->pos;
entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 16);
- if (size > (size_t)((char*)code_buffer->end - (char*)entry)) {
+ if ((char*)entry > (char*)code_buffer->end || size > (size_t)((char*)code_buffer->end - (char*)entry)) {
dasm_free(&dasm_state);
return NULL;
}
@@ -7227,7 +7227,7 @@ void *ir_emit_thunk(ir_code_buffer *code_buffer, void *addr, size_t *size_ptr)
entry = code_buffer->pos;
entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 4);
- if (size > (size_t)((char*)code_buffer->end - (char*)entry)) {
+ if ((char*)entry > (char*)code_buffer->end || size > (size_t)((char*)code_buffer->end - (char*)entry)) {
dasm_free(&dasm_state);
return NULL;
}
diff --git a/ext/opcache/jit/ir/ir_x86.dasc b/ext/opcache/jit/ir/ir_x86.dasc
index dee5867108e..b9e841c67df 100644
--- a/ext/opcache/jit/ir/ir_x86.dasc
+++ b/ext/opcache/jit/ir/ir_x86.dasc
@@ -12243,7 +12243,7 @@ next_block:;
if (ctx->code_buffer) {
entry = ctx->code_buffer->pos;
entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 16);
- if (size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
+ if ((char*)entry > (char*)ctx->code_buffer->end || size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
dasm_free(&data.dasm_state);
ctx->data = NULL;
ctx->status = IR_ERROR_CODE_MEM_OVERFLOW;
@@ -12383,7 +12383,7 @@ const void *ir_emit_exitgroup(uint32_t first_exit_point, uint32_t exit_points_pe
entry = code_buffer->pos;
entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 16);
- if (size > (size_t)((char*)code_buffer->end - (char*)entry)) {
+ if ((char*)entry > (char*)code_buffer->end || size > (size_t)((char*)code_buffer->end - (char*)entry)) {
dasm_free(&dasm_state);
return NULL;
}