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"><p>foo</p></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));