Commit bf2ba7a8006 for php.net
commit bf2ba7a8006f96794307f9184672eee61381b253
Author: David Carlier <devnexen@gmail.com>
Date: Thu Aug 6 20:49:08 2026 +0100
Zend: include() with a non-literal argument reads out of bounds with error_include_args=1.
Fix #23083
RT_CONSTANT() is only valid when op1 is a literal, so a CV or TMP operand
turned a frame offset into a pointer inside the opline array. Read the
operand from the call frame instead unless op1_type is IS_CONST.
Close GH-23095
diff --git a/NEWS b/NEWS
index b6d2b227ce2..7bad8e58adc 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ PHP NEWS
- Core:
. Changed run-tests.php to run test subprocesses without a shell where
possible. (NickSdot)
+ . Fixed GH-23083 (SEGV build_trace_args in zend_exceptions.c with
+ -d error_include_args=On). (David Carlier)
- Curl:
. Improved cURL option validation errors to include the option name.
diff --git a/Zend/tests/gh23083.phpt b/Zend/tests/gh23083.phpt
new file mode 100644
index 00000000000..a731a987967
--- /dev/null
+++ b/Zend/tests/gh23083.phpt
@@ -0,0 +1,32 @@
+--TEST--
+GH-23083 (SEGV in build_trace_args() with error_include_args=On and a non-literal include argument)
+--INI--
+error_include_args=On
+--FILE--
+<?php
+
+$file = 'no_such_file';
+
+/* CV operand */
+include $file;
+
+/* TMP operand */
+include $file . '_2';
+
+/* CV operand holding a reference */
+$ref = &$file;
+include $ref;
+
+?>
+--EXPECTF--
+Warning: include('no_such_file'): Failed to open stream: No such file or directory in %s on line %d
+
+Warning: include('no_such_file'): Failed opening 'no_such_file' for inclusion (include_path='%s') in %s on line %d
+
+Warning: include('no_such_file_2'): Failed to open stream: No such file or directory in %s on line %d
+
+Warning: include('no_such_file_2'): Failed opening 'no_such_file_2' for inclusion (include_path='%s') in %s on line %d
+
+Warning: include('no_such_file'): Failed to open stream: No such file or directory in %s on line %d
+
+Warning: include('no_such_file'): Failed opening 'no_such_file' for inclusion (include_path='%s') in %s on line %d
diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c
index ca91ec0ce12..1b8297881d6 100644
--- a/Zend/zend_exceptions.c
+++ b/Zend/zend_exceptions.c
@@ -637,7 +637,17 @@ ZEND_API zend_string *zend_trace_current_function_args_string(void) {
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);
+ zval *inc_filename;
+
+ switch (execute_data->opline->op1_type) {
+ /* op1 may be CONST, TMP or CV; RT_CONSTANT() is only valid for the former. */
+ case IS_CONST:
+ inc_filename = RT_CONSTANT(execute_data->opline, execute_data->opline->op1);
+ break;
+ default:
+ inc_filename = EX_VAR(execute_data->opline->op1.var);
+ }
+
smart_str str = {0};
build_trace_args(inc_filename, &str);
return smart_str_extract(&str);