Commit fbd2fc72626 for php

commit fbd2fc7262648bfb1394925dc67f90c1bdfd0898
Author: Gina Peter Banyard <girgias@php.net>
Date:   Fri Nov 13 17:04:48 2026 +0000

    tree: use new zend_return_non_interned_string() to prevent SCCP interning

diff --git a/Zend/tests/attributes/deprecated/class_constants/value_unknown_at_compile_time_001.phpt b/Zend/tests/attributes/deprecated/class_constants/value_unknown_at_compile_time_001.phpt
index 78367ffc065..176dc6241fb 100644
--- a/Zend/tests/attributes/deprecated/class_constants/value_unknown_at_compile_time_001.phpt
+++ b/Zend/tests/attributes/deprecated/class_constants/value_unknown_at_compile_time_001.phpt
@@ -1,9 +1,11 @@
 --TEST--
 #[\Deprecated]: Class constant with value unknown at compile time.
+--EXTENSIONS--
+zend_test
 --FILE--
 <?php

-define('SUFFIX', random_int(1, 2) == 1 ? 'a' : 'b');
+define('SUFFIX', zend_return_non_interned_string('a'));

 class Clazz {
 	#[\Deprecated]
@@ -17,5 +19,5 @@ class Clazz {
 ?>
 --EXPECTF--
 Deprecated: Constant Clazz::CONSTANT is deprecated in %s on line %d
-string(7) "Clazz-%c"
+string(7) "Clazz-a"
 bool(true)
diff --git a/Zend/tests/attributes/deprecated/constants/value_unknown_at_compile_time_001.phpt b/Zend/tests/attributes/deprecated/constants/value_unknown_at_compile_time_001.phpt
index a968e26673e..645a1a902f7 100644
--- a/Zend/tests/attributes/deprecated/constants/value_unknown_at_compile_time_001.phpt
+++ b/Zend/tests/attributes/deprecated/constants/value_unknown_at_compile_time_001.phpt
@@ -1,9 +1,11 @@
 --TEST--
 #[\Deprecated]: Constant with value unknown at compile time.
+--EXTENSIONS--
+zend_test
 --FILE--
 <?php

-define('SUFFIX', random_int(1, 2) == 1 ? 'a' : 'b');
+define('SUFFIX', zend_return_non_interned_string('a'));

 #[\Deprecated]
 const CONSTANT = 'Prefix-' . SUFFIX;
@@ -15,5 +17,5 @@
 ?>
 --EXPECTF--
 Deprecated: Constant CONSTANT is deprecated in %s on line %d
-string(8) "Prefix-%c"
+string(8) "Prefix-a"
 bool(true)
diff --git a/Zend/tests/attributes/deprecated/message_004.phpt b/Zend/tests/attributes/deprecated/message_004.phpt
index 74860ba82b7..e766810704f 100644
--- a/Zend/tests/attributes/deprecated/message_004.phpt
+++ b/Zend/tests/attributes/deprecated/message_004.phpt
@@ -1,9 +1,11 @@
 --TEST--
 #[\Deprecated]: Message with value unknown at compile time.
+--EXTENSIONS--
+zend_test
 --FILE--
 <?php

-define('MESSAGE', 'value-' . (random_int(1, 2) == 1 ? 'a' : 'b'));
+define('MESSAGE', 'value-' . zend_return_non_interned_string('a'));

 #[\Deprecated(MESSAGE)]
 function test() {
@@ -13,4 +15,4 @@ function test() {

 ?>
 --EXPECTF--
-Deprecated: Function test() is deprecated, value-%c in %s on line %d
+Deprecated: Function test() is deprecated, value-a in %s on line %d
diff --git a/Zend/tests/error_reporting/bug81652.phpt b/Zend/tests/error_reporting/bug81652.phpt
index a115f590add..c5382ec89b5 100644
--- a/Zend/tests/error_reporting/bug81652.phpt
+++ b/Zend/tests/error_reporting/bug81652.phpt
@@ -1,5 +1,7 @@
 --TEST--
 Bug #81652: The value of error_reporting() gets overridden
+--EXTENSIONS--
+zend_test
 --FILE--
 <?php

diff --git a/ext/curl/tests/refcounted_return_must_not_leak.phpt b/ext/curl/tests/refcounted_return_must_not_leak.phpt
index b4b07a1a4fc..11f3182197b 100644
--- a/ext/curl/tests/refcounted_return_must_not_leak.phpt
+++ b/ext/curl/tests/refcounted_return_must_not_leak.phpt
@@ -2,6 +2,7 @@
 Returning refcounted value from callback must not leak
 --EXTENSIONS--
 curl
+zend_test
 --FILE--
 <?php
 include 'server.inc';
@@ -11,7 +12,7 @@
 $ch = curl_init($url);

 function return_non_interned_string() {
-    return str_repeat('x', random_int(5, 5));
+    return zend_return_non_interned_string('x');
 }

 curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
diff --git a/ext/dom/tests/DOMXPath_callables_errors.phpt b/ext/dom/tests/DOMXPath_callables_errors.phpt
index a34427ebefd..d1d4167445e 100644
--- a/ext/dom/tests/DOMXPath_callables_errors.phpt
+++ b/ext/dom/tests/DOMXPath_callables_errors.phpt
@@ -2,6 +2,7 @@
 registerPHPFunctions() with callables - error cases
 --EXTENSIONS--
 dom
+zend_test
 --FILE--
 <?php

@@ -64,7 +65,7 @@ public static function dump() {}
 $classes = get_declared_classes();

 try {
-    $str = str_repeat($classes[count($classes) - 1] . '::dump', random_int(1, 1));
+    $str = zend_return_non_interned_string($classes[count($classes) - 1] . '::dump');
     $xpath->registerPhpFunctions([$str]);
 } catch (Throwable $e) {
     echo $e::class, ': ', $e->getMessage(), "\n";
diff --git a/ext/dom/tests/gh12002.phpt b/ext/dom/tests/gh12002.phpt
index 2512aa7d23f..9d89e0b7b8d 100644
--- a/ext/dom/tests/gh12002.phpt
+++ b/ext/dom/tests/gh12002.phpt
@@ -2,24 +2,20 @@
 GH-12002 (DOMDocument::encoding memory leak with invalid encoding)
 --EXTENSIONS--
 dom
+zend_test
 --FILE--
 <?php

-function make_nonconst(string $x) {
-    // Defeat SCCP, even with inlining
-    return str_repeat($x, random_int(1, 1));
-}
-
 $dom = new DOMDocument();
-$dom->encoding = make_nonconst('utf-8');
+$dom->encoding = zend_return_non_interned_string('utf-8');
 var_dump($dom->encoding);
 try {
-    $dom->encoding = make_nonconst('foobar');
+    $dom->encoding = zend_return_non_interned_string('foobar');
 } catch (Throwable $e) {
     echo $e::class, ': ', $e->getMessage(), "\n";
 }
 var_dump($dom->encoding);
-$dom->encoding = make_nonconst('utf-16le');
+$dom->encoding = zend_return_non_interned_string('utf-16le');
 var_dump($dom->encoding);
 try {
     $dom->encoding = NULL;
diff --git a/ext/dom/tests/modern/html/parser/Element_innerHTML.phpt b/ext/dom/tests/modern/html/parser/Element_innerHTML.phpt
index 7e76cad0a12..42afd44ea03 100644
--- a/ext/dom/tests/modern/html/parser/Element_innerHTML.phpt
+++ b/ext/dom/tests/modern/html/parser/Element_innerHTML.phpt
@@ -2,6 +2,7 @@
 Test writing Element::$innerHTML on HTML documents
 --EXTENSIONS--
 dom
+zend_test
 --FILE--
 <?php

@@ -20,7 +21,7 @@
 echo $dom->saveXML(), "\n";

 // Create a non-interned string that gets the UTF-8 validity flag added
-$str = str_repeat("my valid string", random_int(2, 2));
+$str = zend_return_non_interned_string("my valid string");
 preg_match('/^.*$/u', $str);
 $el->innerHTML = $str;
 echo $dom->saveXML(), "\n";
@@ -56,7 +57,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <div xmlns="http://www.w3.org/1999/xhtml">invalid�utf-8𐍈𐍈𐍈</div>
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<div xmlns="http://www.w3.org/1999/xhtml">my valid stringmy valid string</div>
+<div xmlns="http://www.w3.org/1999/xhtml">my valid string</div>
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <style xmlns="http://www.w3.org/1999/xhtml">&lt;p&gt;foo&lt;/p&gt;</style>
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
diff --git a/ext/intl/tests/msgfmt_format_error4.phpt b/ext/intl/tests/msgfmt_format_error4.phpt
index 78dc27b4092..f92dab244b7 100644
--- a/ext/intl/tests/msgfmt_format_error4.phpt
+++ b/ext/intl/tests/msgfmt_format_error4.phpt
@@ -2,6 +2,7 @@
 MessageFormatter::format() invalid UTF-8 for arg key or value
 --EXTENSIONS--
 intl
+zend_test
 --INI--
 intl.use_exceptions=On
 --FILE--
@@ -29,7 +30,7 @@
 try {
     var_dump($mf->format(array("foo" => new class {
         function __toString(): string {
-            return str_repeat("\x80", random_int(1, 1));
+            return zend_return_non_interned_string("\x80");
         }
     })));
 } catch (Throwable $e) {
diff --git a/ext/ldap/tests/ldap_set_option_leak_attrvalue_context.phpt b/ext/ldap/tests/ldap_set_option_leak_attrvalue_context.phpt
index 5829ad24faf..acced946ecc 100644
--- a/ext/ldap/tests/ldap_set_option_leak_attrvalue_context.phpt
+++ b/ext/ldap/tests/ldap_set_option_leak_attrvalue_context.phpt
@@ -2,14 +2,15 @@
 ldap_set_option() - Leaks attrvalue and context
 --EXTENSIONS--
 ldap
+zend_test
 --FILE--
 <?php
 require "connect.inc";

 $link = ldap_connect($uri);

-$attrvalue = str_repeat("attrvalue", random_int(1, 1));
-$context = str_repeat("context", random_int(1, 1));
+$attrvalue = zend_return_non_interned_string("attrvalue");
+$context = zend_return_non_interned_string("context");

 $controls = [
     ["oid" => "2.16.840.1.113730.3.4.9", "value" => ["attrvalue" => $attrvalue, "context" => $context, "before" => 0, "after" => 0]],
diff --git a/ext/pcre/tests/preg_match_frameless_leak.phpt b/ext/pcre/tests/preg_match_frameless_leak.phpt
index b97cb86347f..16958033a25 100644
--- a/ext/pcre/tests/preg_match_frameless_leak.phpt
+++ b/ext/pcre/tests/preg_match_frameless_leak.phpt
@@ -1,11 +1,14 @@
 --TEST--
 Memory leak in preg_match() frameless function with invalid regex and object arguments
+--EXTENSIONS--
+pcre
+zend_test
 --FILE--
 <?php
 class Str {
     private $val;
     public function __construct($val) {
-        $this->val = str_repeat($val, random_int(1, 1));
+        $this->val = zend_return_non_interned_string($val);
     }
     public function __toString() {
         return $this->val;
diff --git a/ext/pdo/tests/pdo_fetch_class_by_ref_constructor.phpt b/ext/pdo/tests/pdo_fetch_class_by_ref_constructor.phpt
index 4524980b2c4..db7dedab008 100644
--- a/ext/pdo/tests/pdo_fetch_class_by_ref_constructor.phpt
+++ b/ext/pdo/tests/pdo_fetch_class_by_ref_constructor.phpt
@@ -2,6 +2,7 @@
 PDO Common: PDO::FETCH_CLASS with by-ref constructor and arg by value
 --EXTENSIONS--
 pdo
+zend_test
 --SKIPIF--
 <?php
 $dir = getenv('REDIR_TEST_DIR');
@@ -36,8 +37,7 @@ public function __construct(string &$str)
 }

 $stmt->execute();
-// Use of random_int(10,10) is to defeat SCCP
-var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestByRefCtor', [str_repeat('a', random_int(10,10))]));
+var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestByRefCtor', [zend_return_non_interned_string('a')]));

 ?>
 --CLEAN--
@@ -48,13 +48,13 @@ public function __construct(string &$str)
 ?>
 --EXPECTF--
 Warning: TestByRefCtor::__construct(): Argument #1 ($str) must be passed by reference, value given in %s on line %d
-TestByRefCtor::__construct(aaaaaaaaaa, 1)
+TestByRefCtor::__construct(a, 1)

 Warning: TestByRefCtor::__construct(): Argument #1 ($str) must be passed by reference, value given in %s on line %d
-TestByRefCtor::__construct(aaaaaaaaaa, 2)
+TestByRefCtor::__construct(a, 2)

 Warning: TestByRefCtor::__construct(): Argument #1 ($str) must be passed by reference, value given in %s on line %d
-TestByRefCtor::__construct(aaaaaaaaaa, 3)
+TestByRefCtor::__construct(a, 3)
 array(3) {
   [0]=>
   object(TestByRefCtor)#%d (3) {
@@ -63,7 +63,7 @@ public function __construct(string &$str)
     ["val"]=>
     string(1) "A"
     ["str":"TestByRefCtor":private]=>
-    string(11) "aaaaaaaaaaA"
+    string(2) "aA"
   }
   [1]=>
   object(TestByRefCtor)#%d (3) {
@@ -72,7 +72,7 @@ public function __construct(string &$str)
     ["val"]=>
     string(1) "B"
     ["str":"TestByRefCtor":private]=>
-    string(11) "aaaaaaaaaaB"
+    string(2) "aB"
   }
   [2]=>
   object(TestByRefCtor)#%d (3) {
@@ -81,6 +81,6 @@ public function __construct(string &$str)
     ["val"]=>
     string(1) "C"
     ["str":"TestByRefCtor":private]=>
-    string(11) "aaaaaaaaaaC"
+    string(2) "aC"
   }
 }
diff --git a/ext/pdo_firebird/tests/gh18276.phpt b/ext/pdo_firebird/tests/gh18276.phpt
index 5a1c4b4de29..09c56c2fd4f 100644
--- a/ext/pdo_firebird/tests/gh18276.phpt
+++ b/ext/pdo_firebird/tests/gh18276.phpt
@@ -2,6 +2,7 @@
 GH-18276 (persistent connection - setAttribute(Pdo\Firebird::ATTR_DATE_FORMAT, ..) results in "zend_mm_heap corrupted")
 --EXTENSIONS--
 pdo_firebird
+zend_test
 --SKIPIF--
 <?php require('skipif.inc'); ?>
 --XLEAK--
@@ -23,9 +24,9 @@
         ],
     );
     // Avoid interned
-    $dbh->setAttribute(Pdo\Firebird::ATTR_DATE_FORMAT, str_repeat('Y----m----d', random_int(1, 1)));
-    $dbh->setAttribute(Pdo\Firebird::ATTR_TIME_FORMAT, str_repeat('H::::i::::s', random_int(1, 1)));
-    $dbh->setAttribute(Pdo\Firebird::ATTR_TIMESTAMP_FORMAT, str_repeat('Y----m----d....H::::i::::s', random_int(1, 1)));
+    $dbh->setAttribute(Pdo\Firebird::ATTR_DATE_FORMAT, zend_return_non_interned_string('Y----m----d'));
+    $dbh->setAttribute(Pdo\Firebird::ATTR_TIME_FORMAT, zend_return_non_interned_string('H::::i::::s'));
+    $dbh->setAttribute(Pdo\Firebird::ATTR_TIMESTAMP_FORMAT, zend_return_non_interned_string('Y----m----d....H::::i::::s'));
     unset($dbh);
 }

diff --git a/ext/phar/tests/gh18953.phpt b/ext/phar/tests/gh18953.phpt
index ff48e457cc9..bef854b89c8 100644
--- a/ext/phar/tests/gh18953.phpt
+++ b/ext/phar/tests/gh18953.phpt
@@ -3,13 +3,14 @@
 --EXTENSIONS--
 phar
 zlib
+zend_test
 --INI--
 phar.readonly=0
 --FILE--
 <?php

 $phar = new Phar(__DIR__ . "/gh18953.phar");
-$phar->addFromString("file", str_repeat("123", random_int(1, 1)));
+$phar->addFromString("file", zend_return_non_interned_string("123"));
 $phar->addEmptyDir("dir");
 $phar2 = $phar->compress(Phar::GZ);

diff --git a/ext/phar/tests/openssl_sign_invalid_polyfill_return_value.phpt b/ext/phar/tests/openssl_sign_invalid_polyfill_return_value.phpt
index 37c14188edf..7dbde3e909f 100644
--- a/ext/phar/tests/openssl_sign_invalid_polyfill_return_value.phpt
+++ b/ext/phar/tests/openssl_sign_invalid_polyfill_return_value.phpt
@@ -2,6 +2,7 @@
 openssl_sign() polyfill with wrong return value
 --EXTENSIONS--
 phar
+zend_test
 --SKIPIF--
 <?php
 if (getenv('SKIP_SLOW_TESTS')) die('skip');
@@ -14,7 +15,7 @@
 $fname = __DIR__ . '/' . basename(__FILE__, '.php') . '.tar';

 function openssl_sign() {
-    return str_repeat('foobar', random_int(1, 1));
+    return zend_return_non_interned_string('foobar');
 }

 $phar = new PharData($fname);
diff --git a/ext/session/tests/user_session_module/gh_gc_retval_leak.phpt b/ext/session/tests/user_session_module/gh_gc_retval_leak.phpt
index f04f36c2276..685ac48e64c 100644
--- a/ext/session/tests/user_session_module/gh_gc_retval_leak.phpt
+++ b/ext/session/tests/user_session_module/gh_gc_retval_leak.phpt
@@ -5,6 +5,7 @@
 session.save_handler=files
 --EXTENSIONS--
 session
+zend_test
 --FILE--
 <?php
 ob_start();
@@ -17,7 +18,7 @@ function() { return true; },
     function(string $id): string|false { return ""; },
     function(string $id, string $data) { return true; },
     function(string $id) { return true; },
-    function(int $max) { return str_repeat("x", random_int(100, 100)); }
+    function(int $max) { return zend_return_non_interned_string("x"); }
 );

 session_start();
diff --git a/ext/snmp/tests/gh16959.phpt b/ext/snmp/tests/gh16959.phpt
index f76fa61e1f7..ac8ed8eac8a 100644
--- a/ext/snmp/tests/gh16959.phpt
+++ b/ext/snmp/tests/gh16959.phpt
@@ -2,6 +2,7 @@
 snmpget() modifies object_id array source
 --EXTENSIONS--
 snmp
+zend_test
 --SKIPIF--
 <?php
 require_once(__DIR__.'/skipif.inc');
@@ -25,17 +26,17 @@
 }

 try {
-	snmp2_set($hostname, $communityWrite, $bad_object_ids, array(new stdClass()), array(null));
+	snmp2_set($hostname, $communityWrite, $bad_object_ids, [new stdClass()], [null]);
 } catch (Throwable $e) {
 	echo $e->getMessage() . PHP_EOL;
 }
 try {
-	snmp2_set($hostname, $communityWrite, $bad_object_ids, array("toolongtype"), array(null));
+	snmp2_set($hostname, $communityWrite, $bad_object_ids, ["toolongtype"], [null]);
 } catch (Throwable $e) {
 	echo $e->getMessage() . PHP_EOL;
 }
 try {
-	snmp2_set($hostname, $communityWrite, $bad_object_ids, array(str_repeat("onetoomuch", random_int(1, 1))), array(null));
+	snmp2_set($hostname, $communityWrite, $bad_object_ids, [zend_return_non_interned_string("onetoomuch")], [null]);
 } catch (Throwable $e) {
 	echo $e->getMessage();
 }
diff --git a/ext/snmp/tests/snmp-object-setSecurity-contextName.phpt b/ext/snmp/tests/snmp-object-setSecurity-contextName.phpt
index 95055e2be8f..256ebd1d634 100644
--- a/ext/snmp/tests/snmp-object-setSecurity-contextName.phpt
+++ b/ext/snmp/tests/snmp-object-setSecurity-contextName.phpt
@@ -2,6 +2,7 @@
 SNMP::setSecurity() - the context name is copied
 --EXTENSIONS--
 snmp
+zend_test
 --SKIPIF--
 <?php
 require_once(__DIR__.'/skipif.inc');
@@ -11,7 +12,7 @@
 require_once(__DIR__.'/snmp_include.inc');

 $session = new SNMP(SNMP::VERSION_3, $hostname, $rwuser, $timeout, $retries);
-$context = str_repeat('c', 5) . random_int(10, 99);
+$context = zend_return_non_interned_string('c');
 $session->setSecurity('authPriv', 'MD5', $auth_pass, 'AES', $priv_pass, $context);
 unset($context);
 // The agent does not know this context, only the lifetime of the name matters.
diff --git a/ext/standard/tests/array/gh17977.phpt b/ext/standard/tests/array/gh17977.phpt
index 4a4f344dc47..b85952a3213 100644
--- a/ext/standard/tests/array/gh17977.phpt
+++ b/ext/standard/tests/array/gh17977.phpt
@@ -2,12 +2,12 @@
 array_any() / array_all() leak
 --DESCRIPTION--
 Found in GH-16831#issuecomment-2700410631
+--EXTENSIONS--
+zend_test
 --FILE--
 <?php

-// Don't touch this str_repeat + random_int combination,
-// this is to circumvent SCCP and interning
-$key = str_repeat('abc', random_int(3, 3));
+$key = zend_return_non_interned_string('abc');

 var_dump(array_any([$key => 1], static fn () => true));
 var_dump(array_all([$key => 1], static fn () => false));