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;
 	}