Commit 269f7b762b5 for php

commit 269f7b762b5938915a6a2792a8b9b0d81edc664a
Author: ndossche <7771979+ndossche@users.noreply.github.com>
Date:   Sat Oct 10 15:31:32 2026 +0200

    Fix exception checks due to NAN warnings and object empty()'s

    The empty() check for objects must be backported to 8.4, the NAN problem
    is new since 320fe2975b.

    Closes GH-24241.

diff --git a/NEWS b/NEWS
index 34f540d39b4..262f3f4fd7a 100644
--- a/NEWS
+++ b/NEWS
@@ -30,6 +30,7 @@ PHP                                                                        NEWS
   . Fix type inference of ADD_ARRAY_UNPACK with integer keys. (ndossche)
   . Fix too wide type inference for ASSIGN_DIM_OP. (ndossche)
   . Fix OSS-Fuzz #568005340 (FETCH_DIM_FUNC_ARG partial conversion). (ndossche)
+  . Fix exception checks due to NAN warnings and object empty()'s. (ndossche)

 - Standard:
   . Fixed password_get_info() and password_needs_rehash() accepting malformed
diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c
index b862fe48361..af31ec757be 100644
--- a/Zend/Optimizer/zend_inference.c
+++ b/Zend/Optimizer/zend_inference.c
@@ -5030,7 +5030,6 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op
 		case ZEND_SWITCH_STRING:
 		case ZEND_MATCH:
 		case ZEND_ISSET_ISEMPTY_VAR:
-		case ZEND_ISSET_ISEMPTY_CV:
 		case ZEND_FUNC_NUM_ARGS:
 		case ZEND_FUNC_GET_ARGS:
 		case ZEND_COPY_TMP:
@@ -5118,7 +5117,14 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op
 		case ZEND_JMPZ_EX:
 		case ZEND_JMPNZ_EX:
 		case ZEND_JMP_SET:
-			return (t1 & MAY_BE_OBJECT);
+			/* NAN cast to bool will warn */
+			return (t1 & (MAY_BE_OBJECT|MAY_BE_DOUBLE));
+		case ZEND_ISSET_ISEMPTY_CV:
+			if (!(opline->extended_value & ZEND_ISEMPTY)) {
+				return 0;
+			}
+			/* empty() casts to bool: objects may have a cast handler, and NAN will warn */
+			return (t1 & (MAY_BE_OBJECT|MAY_BE_DOUBLE));
 		case ZEND_BOOL:
 		case ZEND_BOOL_NOT:
 			/* NAN Cast to bool will warn, but if we have a range it is fine */
diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c
index ec745d0613a..471cf55c654 100644
--- a/ext/opcache/jit/zend_jit_ir.c
+++ b/ext/opcache/jit/zend_jit_ir.c
@@ -7753,6 +7753,8 @@ static int zend_jit_bool_jmpznz(zend_jit_ctx *jit, const zend_op *opline, uint32
 		ir_IF_TRUE_cold(if_val);
 		jit_SET_EX_OPLINE(jit, opline);
 		ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_nan_coerced_to_type_warning));
+		/* The warning may be turned into an exception by an error handler */
+		zend_jit_check_exception_undef_result(jit, opline);
 		ir_MERGE_WITH_EMPTY_FALSE(if_val);

 		ref = ir_NE(dval, ir_CONST_DOUBLE(0.0));
diff --git a/ext/opcache/tests/jit/nan_to_bool_exception.phpt b/ext/opcache/tests/jit/nan_to_bool_exception.phpt
new file mode 100644
index 00000000000..c612c008f31
--- /dev/null
+++ b/ext/opcache/tests/jit/nan_to_bool_exception.phpt
@@ -0,0 +1,46 @@
+--TEST--
+JIT: NAN to bool coercion warning promoted to exception
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit=1205
+--EXTENSIONS--
+opcache
+--FILE--
+<?php
+set_error_handler(function ($no, $str) {
+    throw new Exception($str);
+});
+
+function jmpz(float $d) {
+    if ($d) {
+        echo "side effect\n";
+    }
+    echo "side effect\n";
+}
+
+function jmp_set(float $d) {
+    $r = $d ?: 1;
+    echo "side effect\n";
+    return $r;
+}
+
+function isempty(float $d) {
+    $r = empty($d);
+    echo "side effect\n";
+    return $r;
+}
+
+foreach (["jmpz", "jmp_set", "isempty"] as $f) {
+    try {
+        $f(NAN);
+    } catch (Exception $e) {
+        echo "$f: ", $e->getMessage(), "\n";
+    }
+}
+?>
+--EXPECT--
+jmpz: unexpected NAN value was coerced to bool
+jmp_set: unexpected NAN value was coerced to bool
+isempty: unexpected NAN value was coerced to bool