Commit 97202d9d84 for php.net

commit 97202d9d8401ce88b65d604df1f45af43c9a04a1
Author: Nikita Popov <nikita.ppv@gmail.com>
Date:   Fri Oct 16 17:23:10 2020 +0200

    Make sure output start filename is not freed early

    As filenames are no longer interned, we need to keep a reference
    to the zend_string to make sure it isn't freed.

    To avoid a nominal source compatibility break, create a new member
    in the globals.

diff --git a/Zend/tests/output_started_at_eval.phpt b/Zend/tests/output_started_at_eval.phpt
new file mode 100644
index 0000000000..4bb331c76f
--- /dev/null
+++ b/Zend/tests/output_started_at_eval.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Output start at eval()
+--FILE--
+<?php
+eval('echo "Foo\n";');
+header('Foo: Bar');
+?>
+--EXPECTF--
+Foo
+
+Warning: Cannot modify header information - headers already sent by (output started at %s(2) : eval()'d code:1) in %s on line %d
diff --git a/main/output.c b/main/output.c
index c895d3856e..cffadede80 100644
--- a/main/output.c
+++ b/main/output.c
@@ -103,16 +103,20 @@ static size_t (*php_output_direct)(const char *str, size_t str_len) = php_output
 static void php_output_header(void)
 {
 	if (!SG(headers_sent)) {
-		if (!OG(output_start_filename)) {
+		if (!OG(output_start_filename_str)) {
 			if (zend_is_compiling()) {
-				OG(output_start_filename) = ZSTR_VAL(zend_get_compiled_filename());
+				OG(output_start_filename_str) = zend_get_compiled_filename();
 				OG(output_start_lineno) = zend_get_compiled_lineno();
 			} else if (zend_is_executing()) {
-				OG(output_start_filename) = zend_get_executed_filename();
+				OG(output_start_filename_str) = zend_get_executed_filename_ex();
 				OG(output_start_lineno) = zend_get_executed_lineno();
 			}
+			if (OG(output_start_filename_str)) {
+				zend_string_addref(OG(output_start_filename_str));
+			}
 #if PHP_OUTPUT_DEBUG
-			fprintf(stderr, "!!! output started at: %s (%d)\n", OG(output_start_filename), OG(output_start_lineno));
+			fprintf(stderr, "!!! output started at: %s (%d)\n",
+				ZSTR_VAL(OG(output_start_filename_str)), OG(output_start_lineno));
 #endif
 		}
 		if (!php_header()) {
@@ -190,6 +194,11 @@ PHPAPI void php_output_deactivate(void)
 		}
 		zend_stack_destroy(&OG(handlers));
 	}
+
+	if (OG(output_start_filename_str)) {
+		zend_string_release(OG(output_start_filename_str));
+		OG(output_start_filename_str) = NULL;
+	}
 }
 /* }}} */

@@ -749,7 +758,7 @@ PHPAPI void php_output_set_implicit_flush(int flush)
  * Get the file name where output has started */
 PHPAPI const char *php_output_get_start_filename(void)
 {
-	return OG(output_start_filename);
+	return ZSTR_VAL(OG(output_start_filename_str));
 }
 /* }}} */

diff --git a/main/php_output.h b/main/php_output.h
index 60f389b2b5..eba63e6039 100644
--- a/main/php_output.h
+++ b/main/php_output.h
@@ -137,9 +137,10 @@ ZEND_BEGIN_MODULE_GLOBALS(output)
 	zend_stack handlers;
 	php_output_handler *active;
 	php_output_handler *running;
-	const char *output_start_filename;
+	const char *output_start_filename; /* TODO: Unused, remove */
 	int output_start_lineno;
 	int flags;
+	zend_string *output_start_filename_str;
 ZEND_END_MODULE_GLOBALS(output)

 PHPAPI ZEND_EXTERN_MODULE_GLOBALS(output)