Commit 77a7d34ab26 for php.net

commit 77a7d34ab26676a318eba6172b5f4dc19dc7c051
Author: Calvin Buckley <calvinb@php.net>
Date:   Wed Jul 22 16:18:36 2026 -0300

    Fix GH-22849: error_include_args=1 mishandled for include() (#22851)

    include and friends aren't functions, but constructs of the engine.
    Special-case them and snarf their argument for display.

diff --git a/Zend/tests/gh22849.phpt b/Zend/tests/gh22849.phpt
new file mode 100644
index 00000000000..a38c64baf54
--- /dev/null
+++ b/Zend/tests/gh22849.phpt
@@ -0,0 +1,31 @@
+--TEST--
+PHP 8.6 error_include_args=1 mishandled for include()
+--INI--
+error_include_args=On
+--FILE--
+<?php
+
+function foo() {
+    include("does not exist");
+    include_once("does not exist");
+    require("does not exist");
+}
+
+foo(1, 2);
+?>
+--EXPECTF--
+Warning: include('does not exist'): Failed to open stream: No such file or directory in %s on line %d
+
+Warning: include('does not exist'): Failed opening 'does not exist' for inclusion (include_path='%s') in %s on line %d
+
+Warning: include_once('does not exist'): Failed to open stream: No such file or directory in %s on line %d
+
+Warning: include_once('does not exist'): Failed opening 'does not exist' for inclusion (include_path='%s') in %s on line %d
+
+Warning: require('does not exist'): Failed to open stream: No such file or directory in %s on line %d
+
+Fatal error: Uncaught Error: Failed opening required 'does not exist' (include_path='%s') in %s:%d
+Stack trace:
+#0 %s(%d): foo(1, 2)
+#1 {main}
+  thrown in %s on line %d
diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c
index a1301b8c20b..ca91ec0ce12 100644
--- a/Zend/zend_exceptions.c
+++ b/Zend/zend_exceptions.c
@@ -630,6 +630,19 @@ ZEND_API zend_string *zend_trace_function_args_to_string(const HashTable *frame)
 /* {{{ Gets the currently executing function's arguments as a string. Used by php_verror. */
 ZEND_API zend_string *zend_trace_current_function_args_string(void) {
 	zend_string *dynamic_params = NULL;
+	/* Special case: require_once/include_once aren't functions, but we
+	 * want to capture their arguments anyways, for i.e. file not found.
+	 */
+	zend_execute_data *execute_data = EG(current_execute_data);
+	if (execute_data && execute_data->func
+			&& ZEND_USER_CODE(execute_data->func->common.type)
+			&& (execute_data->opline->opcode == ZEND_INCLUDE_OR_EVAL)) {
+		zval *inc_filename = RT_CONSTANT(execute_data->opline, execute_data->opline->op1);
+		smart_str str = {0};
+		build_trace_args(inc_filename, &str);
+		return smart_str_extract(&str);
+	}
+
 	/* get a backtrace to snarf function args */
 	zval backtrace;
 	zend_fetch_debug_backtrace(&backtrace, /* skip_last */ 0, /* options */ 0, /* limit */ 1);