mirror of
https://github.com/php/php-src.git
synced 2026-10-28 09:46:46 +08:00
Merge branch 'PHP-8.5' into PHP-8.6
* PHP-8.5: Add NEWS entry Avoid state corruption via bailout
This commit is contained in:
424 files changed
+11592
-1035
No files matched your search
@@ -3,6 +3,9 @@ PHP NEWS
|
||||
?? ??? ????, PHP 8.6.0RC4
|
||||
|
||||
- Core:
|
||||
. Fixed GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp (Avoid state corruption via
|
||||
bailout). (CVE-2026-109618, CVE-2026-109619) (Arnaud, ilutov, Jakub Zelenka,
|
||||
ndossche, Nicolas Grekas)
|
||||
. Fixed bug GH-24184 (System ID not being reinitialized after an Apache
|
||||
graceful restart, potentially causing incompatible OPcache file cache
|
||||
entries to be reused). (Levi Morrison)
|
||||
|
||||
@@ -16,9 +16,9 @@ if ($zend_mm_enabled === "0") {
|
||||
<?php
|
||||
ini_set('display_errors',true);
|
||||
$mb=148;
|
||||
$var = '';
|
||||
$var = [];
|
||||
for ($i=0; $i<=$mb; $i++) {
|
||||
$var.= str_repeat('a',1*1024*1024);
|
||||
$var[] = str_repeat('a',1*1024*1024);
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Bug #76846: Segfault in shutdown function after memory limit error
|
||||
--INI--
|
||||
memory_limit=33M
|
||||
zend.enable_gc=0
|
||||
--SKIPIF--
|
||||
<?php
|
||||
$zend_mm_enabled = getenv("USE_ZEND_ALLOC");
|
||||
@@ -12,13 +13,18 @@ if ($zend_mm_enabled === "0") {
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class C {
|
||||
public $c;
|
||||
public function __construct() {
|
||||
$this->c = $this;
|
||||
}
|
||||
}
|
||||
register_shutdown_function(function() {
|
||||
new stdClass;
|
||||
new C;
|
||||
});
|
||||
|
||||
$ary = [];
|
||||
while (true) {
|
||||
$ary[] = new stdClass;
|
||||
new C;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Bug #54268 (Double free when destroy_zend_class fails)
|
||||
--INI--
|
||||
memory_limit=8M
|
||||
opcache.jit=disable
|
||||
--SKIPIF--
|
||||
<?php
|
||||
$zend_mm_enabled = getenv("USE_ZEND_ALLOC");
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Backtrace args of a #[SensitiveParameter] variadic called with named arguments
|
||||
--FILE--
|
||||
<?php
|
||||
class E extends Exception {}
|
||||
|
||||
function outer(#[SensitiveParameter] ...$args) {
|
||||
return new E();
|
||||
}
|
||||
|
||||
var_dump(outer(a: 1, b: 'secret')->getTrace()[0]['args']);
|
||||
?>
|
||||
--EXPECT--
|
||||
array(2) {
|
||||
["a"]=>
|
||||
object(SensitiveParameterValue)#2 (0) {
|
||||
}
|
||||
["b"]=>
|
||||
object(SensitiveParameterValue)#3 (0) {
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,5 @@
|
||||
--TEST--
|
||||
Fiber::getReturn() after bailout
|
||||
--SKIPIF--
|
||||
<?php
|
||||
$zend_mm_enabled = getenv("USE_ZEND_ALLOC");
|
||||
if ($zend_mm_enabled === "0") {
|
||||
die("skip Zend MM disabled");
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@@ -16,13 +9,13 @@ register_shutdown_function(static function (): void {
|
||||
});
|
||||
|
||||
$fiber = new Fiber(static function (): void {
|
||||
str_repeat('X', PHP_INT_MAX);
|
||||
var_dump(new class { public function __debugInfo() { return ''; } }); // cause a bailout
|
||||
});
|
||||
$fiber->start();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) %sget-return-after-bailout.php on line %d
|
||||
Fatal error: __debugInfo() must return an array in %s on line %d
|
||||
|
||||
Fatal error: Uncaught FiberError: Cannot get fiber return value: The fiber exited with a fatal error in %sget-return-after-bailout.php:%d
|
||||
Stack trace:
|
||||
|
||||
@@ -8,7 +8,7 @@ if (PHP_OS_FAMILY === 'Windows') {
|
||||
if (getenv("USE_ZEND_ALLOC") === "0") die("skip ZMM is disabled");
|
||||
?>
|
||||
--INI--
|
||||
memory_limit=2M
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@@ -29,5 +29,4 @@ while (1) {
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Success
|
||||
Fatal error: Allowed memory size of %s bytes exhausted%s(tried to allocate %s bytes) in %s on line %d
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
@@ -29,5 +29,4 @@ while (1) {
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Success
|
||||
Fatal error: Allowed memory size of %s bytes exhausted%s(tried to allocate %s bytes) in %s on line %d
|
||||
Fatal error: Allowed memory size of 2097152 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
@@ -0,0 +1,20 @@
|
||||
--TEST--
|
||||
OOM SplFixedArray::__unserialize()
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$elems = [];
|
||||
for ($i = 0; $i < 64*1024; $i++) {
|
||||
$elems[] = "i:$i;N;";
|
||||
}
|
||||
$payload = 'O:13:"SplFixedArray":' . count($elems) . ':{' . implode('', $elems) . '}';
|
||||
|
||||
$pad = str_repeat('a', max(10*1024*1024 - memory_get_usage(true) - 512*1024, 1));
|
||||
|
||||
unserialize($payload);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 11
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
OOM SplFixedArray::fromArray() 003
|
||||
--INI--
|
||||
memory_limit=16M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = new SplFixedArray();
|
||||
for ($i = 0; $i < 128*1024; $i++) {
|
||||
@$a->{$i} = 0;
|
||||
}
|
||||
|
||||
$pad = str_repeat('a', max(16*1024*1024 - memory_get_usage(true) - 512*1024, 1));
|
||||
|
||||
$a->__wakeup();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Deprecated: Method SplFixedArray::__wakeup() is deprecated since 8.4, this method is obsolete, as serialization hooks are provided by __unserialize() and __serialize() in %s on line %d
|
||||
|
||||
Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 10
|
||||
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
OOM SplFixedArray copy ctor
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = new SplFixedArray(64*1024);
|
||||
|
||||
$pad = str_repeat('a', max(10*1024*1024 - memory_get_usage(true) - 1*1024*1024, 1));
|
||||
|
||||
clone $a;
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 7
|
||||
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
OOM SplFixedArray::fromArray()
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
SplFixedArray::fromArray([10*1024*1024 => 0], true);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
OOM SplFixedArray::fromArray() 002
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$array = array_fill(0, 128*1024, 0);
|
||||
$pad = str_repeat('a', max(10*1024*1024 - memory_get_usage(true) - 512*1024, 1));
|
||||
SplFixedArray::fromArray($array, false);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 5
|
||||
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
OOM: shutdown functions run after an OOM raised at the end of the main script
|
||||
--INI--
|
||||
memory_limit=8M
|
||||
opcache.optimization_level=0
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
register_shutdown_function(function () {
|
||||
echo "Shutdown function called\n";
|
||||
});
|
||||
|
||||
function test() {
|
||||
$a = str_repeat('a', 3 * 1024 * 1024);
|
||||
$b = $a . $a;
|
||||
echo "Done\n";
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Done
|
||||
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
Shutdown function called
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
OOM array_fill() packed
|
||||
--INI--
|
||||
memory_limit=100M
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_INT_SIZE !== 8) {
|
||||
die('skip 64-bit only');
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_fill(0, 1024*1024*1024-1, (string)time()));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
OOM array_fill() mixed
|
||||
--INI--
|
||||
memory_limit=100M
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_INT_SIZE !== 8) {
|
||||
die('skip 64-bit only');
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_fill(-1, 1024*1024*1024-1, (string)time()));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
OOM array_fill() packed > HT_MAX_SIZE
|
||||
--INI--
|
||||
memory_limit=100M
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_INT_SIZE !== 8) {
|
||||
die('skip 64-bit only');
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_fill(0, 1024*1024*1024+1, (string)time()));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Possible integer overflow in memory allocation (1073741825 * 32 + 32) in %s on line 3
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
OOM array_fill() mixed > HT_MAX_SIZE
|
||||
--INI--
|
||||
memory_limit=100M
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_INT_SIZE !== 8) {
|
||||
die('skip 64-bit only');
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_fill(-1, 1024*1024*1024+1, (string)time()));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Possible integer overflow in memory allocation (1073741825 * 32 + 32) in %s on line 3
|
||||
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
OOM array_pad left packed
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_pad([1,2,3], -1*1024*1024, (string)time()));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
OOM array_pad right packed
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_pad([1,2,3], 1024*1024, (string)time()));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
OOM array_pad left mixed
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_pad(['foo' => 'bar'], -1*1024*1024, (string)time()));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
OOM array_pad right mixed
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_pad(['foo' => 'bar'], 1024*1024, (string)time()));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
OOM array_pad left packed, non-refcounted pad value
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_pad([1,2,3], -1*1024*1024, 0x4141414141));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
OOM array_pad right packed, non-refcounted pad value
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_pad([1,2,3], 1024*1024, 0x4141414141));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
OOM array_pad left mixed, non-refcounted pad value
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_pad(['foo' => 'bar'], -1*1024*1024, 0x4141414141));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
OOM array_pad right mixed, non-refcounted pad value
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(array_pad(['foo' => 'bar'], 1024*1024, 0x4141414141));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
OOM OOM in zend_call_function()
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--ENV--
|
||||
call_user_func=call_user_func
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = [];
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
/* Check that call_user_func() doesn't reset vm_interrupt without checking for OOMs */
|
||||
$a[] = getenv('call_user_func')('str_repeat', 'a', 10*1024*1024);
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 6
|
||||
@@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
OOM zend_call_function() after OOM: destructor called by an internal function
|
||||
--INI--
|
||||
memory_limit=8M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public function __destruct() {
|
||||
echo "not reached\n";
|
||||
}
|
||||
}
|
||||
|
||||
/* array_splice() allocates the new table first, which crosses the soft limit,
|
||||
* then destroys the removed element. The destructor call goes through
|
||||
* zend_call_known_function(), which used to bailout with "Couldn't execute method"
|
||||
* instead of the OOM. */
|
||||
$n = 200000;
|
||||
$arr = range(1, $n);
|
||||
$arr[$n - 1] = new A;
|
||||
array_splice($arr, $n - 1, 1);
|
||||
|
||||
echo "not reached\n";
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of %d bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
@@ -0,0 +1,39 @@
|
||||
--TEST--
|
||||
OOM zend_call_function() after OOM: delayed __unserialize() call
|
||||
--INI--
|
||||
memory_limit=8M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class U {
|
||||
public function __unserialize(array $data): void {
|
||||
echo "not reached\n";
|
||||
}
|
||||
}
|
||||
|
||||
register_shutdown_function(function () {
|
||||
/* The delayed call happens in var_destroy(), which used to bail out with
|
||||
* "Couldn't execute method" */
|
||||
var_dump(unserialize('a:1:{i:0;R:1;}'));
|
||||
});
|
||||
|
||||
/* An object with __unserialize(), then 40000 one-element arrays: ~760 KB
|
||||
* serialized, ~10 MB unserialized. */
|
||||
$n = 40000;
|
||||
$ser = 'a:' . ($n + 1) . ':{i:0;O:1:"U":1:{s:1:"a";i:1;}';
|
||||
for ($i = 1; $i <= $n; $i++) {
|
||||
$ser .= 'i:' . $i . ';a:1:{i:0;i:0;}';
|
||||
}
|
||||
$ser .= '}';
|
||||
|
||||
unserialize($ser);
|
||||
|
||||
echo "not reached\n";
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of %d bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
array(1) {
|
||||
[0]=>
|
||||
*RECURSION*
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
OOM: debug_backtrace() doesn't reach hard limit
|
||||
--INI--
|
||||
memory_limit=8M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function f(int $n) {
|
||||
if ($n > 0) {
|
||||
f($n - 1);
|
||||
return;
|
||||
}
|
||||
debug_backtrace();
|
||||
}
|
||||
|
||||
f(30000);
|
||||
|
||||
echo "not reached\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
OOM: debug_backtrace() doesn't reach hard limit - args
|
||||
--INI--
|
||||
memory_limit=8M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function f(int $n) {
|
||||
if ($n > 0) {
|
||||
f($n - 1, ...$GLOBALS['args']);
|
||||
return;
|
||||
}
|
||||
debug_backtrace();
|
||||
}
|
||||
|
||||
$args = array_fill(0, 512, 1);
|
||||
f(680, ...$args);
|
||||
|
||||
echo "not reached\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
@@ -0,0 +1,29 @@
|
||||
--TEST--
|
||||
OOM: debug_backtrace() doesn't reach hard limit - named args
|
||||
--INI--
|
||||
memory_limit=8M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
/* A variadic is required: extra named args are only accepted by a function
|
||||
* that collects them. */
|
||||
function f(int $n, ...$rest) {
|
||||
if ($n > 0) {
|
||||
f($n - 1, ...$GLOBALS['named']);
|
||||
return;
|
||||
}
|
||||
debug_backtrace();
|
||||
}
|
||||
|
||||
$named = [];
|
||||
for ($i = 0; $i < 512; $i++) {
|
||||
$named["a$i"] = 1;
|
||||
}
|
||||
$GLOBALS['named'] = $named;
|
||||
|
||||
f(450, ...$named);
|
||||
|
||||
echo "not reached\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
@@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
OOM: the message returned by error_get_last() can outlive the error state
|
||||
--INI--
|
||||
memory_limit=8M
|
||||
opcache.optimization_level=0
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
register_shutdown_function(function () {
|
||||
$error = error_get_last();
|
||||
error_clear_last();
|
||||
echo $error['message'], "\n";
|
||||
});
|
||||
|
||||
function test() {
|
||||
$a = [];
|
||||
while (true) {
|
||||
$a[] = str_repeat('a', 1024);
|
||||
}
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes)
|
||||
@@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
OOM: Exception constructor doesn't reach hard limit while fetching backtrace
|
||||
--INI--
|
||||
memory_limit=8M
|
||||
zend.exception_ignore_args=0
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function f(int $n) {
|
||||
if ($n > 0) {
|
||||
f($n - 1);
|
||||
return;
|
||||
}
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
try {
|
||||
f(30000);
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
echo "not reached\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
OOM: Hard limit exceeded
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
||||
function f() {
|
||||
zend_test_emalloc(1024*1024*1024);
|
||||
}
|
||||
|
||||
function shutdown_function() {
|
||||
echo "Not executed\n";
|
||||
}
|
||||
|
||||
register_shutdown_function('shutdown_function');
|
||||
f();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Hard memory limit of 20971520 bytes exhausted %S(tried to allocate %d bytes) in %s on line 5
|
||||
|
||||
Termsig=9
|
||||
@@ -0,0 +1,42 @@
|
||||
--TEST--
|
||||
OOM: Hard limit exceeded during compilation
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
if (!function_exists('str_increment')) {
|
||||
function str_increment(string $s) {
|
||||
$s++;
|
||||
return $s;
|
||||
}
|
||||
}
|
||||
|
||||
$fname = __DIR__ . '/OOM_hard_limit_exceeded_during_complilation.test.php';
|
||||
$fd = fopen($fname, 'w');
|
||||
|
||||
fprintf($fd, "<?php\n");
|
||||
|
||||
$name = str_repeat('A', 100);
|
||||
for ($i = 0; $i < 10000; $i++) {
|
||||
fprintf(
|
||||
$fd,
|
||||
"class %s { public \$a; public \$b; function f() {} function g() {} }\n",
|
||||
$name,
|
||||
);
|
||||
$name = str_increment($name);
|
||||
}
|
||||
|
||||
fclose($fd);
|
||||
|
||||
require $fname;
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
unlink(__DIR__ . '/OOM_hard_limit_exceeded_during_complilation.test.php');
|
||||
?>
|
||||
--EXPECTF--
|
||||
Hard memory limit of 20971520 bytes %s (tried to allocate %d bytes) in %s on line %d
|
||||
|
||||
Termsig=9
|
||||
@@ -0,0 +1,38 @@
|
||||
--TEST--
|
||||
OOM: zend_interrupt_function
|
||||
--EXTENSIONS--
|
||||
pcntl
|
||||
posix
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
// Handle signals from a zend_interrupt_function
|
||||
pcntl_async_signals(true);
|
||||
|
||||
$handled = 0;
|
||||
|
||||
pcntl_signal(SIGTERM, function () use (&$handled) {
|
||||
echo "Handled SIGTERM\n";
|
||||
if (++$handled >= 10) {
|
||||
exit;
|
||||
}
|
||||
});
|
||||
|
||||
$a = [];
|
||||
for ($i = 0; ; $i++) {
|
||||
$a[0] = $i;
|
||||
posix_kill(posix_getpid(), SIGTERM);
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Handled SIGTERM
|
||||
Handled SIGTERM
|
||||
Handled SIGTERM
|
||||
Handled SIGTERM
|
||||
Handled SIGTERM
|
||||
Handled SIGTERM
|
||||
Handled SIGTERM
|
||||
Handled SIGTERM
|
||||
Handled SIGTERM
|
||||
Handled SIGTERM
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Delayed OOM while a call frame is only partially built
|
||||
--DESCRIPTION--
|
||||
A delayed OOM throws from the VM interrupt handler, which runs between two
|
||||
oplines. Argument unpacking grows test()'s frame past a VM stack page, so it is
|
||||
ZEND_CALL_ALLOCATED and owns the page; the interrupt is then delivered after the
|
||||
explode() call, while that frame is still pending.
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function test(...$args) {}
|
||||
|
||||
$args = array_fill(0, 20000, 1);
|
||||
$str = str_repeat('abcdefgh,', 300);
|
||||
|
||||
test(...$args, ...[explode(',', $str)]);
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECT--
|
||||
===DONE===
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
Delayed OOM while a call frame is only partially built (fiber VM stack)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function test(...$args) {}
|
||||
|
||||
$fiber = new Fiber(function () {
|
||||
$args = array_fill(0, 2000, 1);
|
||||
$str = str_repeat('abcdefgh,', 100);
|
||||
test(...$args, ...[explode(',', $str)]);
|
||||
});
|
||||
$fiber->start();
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECT--
|
||||
===DONE===
|
||||
@@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
OOM json_decode() array
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$elems = '0'.str_repeat(',0', 1024*1024);
|
||||
$json = '[' . $elems . ']';
|
||||
var_dump(json_decode($json));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 5
|
||||
@@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
OOM json_decode() nested arrays
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$depth = 1024;
|
||||
$nested = str_repeat('[', $depth) . str_repeat(']', $depth);
|
||||
$json = '[' . $nested . str_repeat(','.$nested, 1024) . ']';
|
||||
var_dump(json_decode($json, depth: $depth+2));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 6
|
||||
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
OOM json_decode() object
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$chunks = [];
|
||||
$chunksize = 64;
|
||||
for ($i = 1; $i < 128*1024; $i++) {
|
||||
if (isset($chunks[$i % $chunksize])) {
|
||||
$chunks[$i % $chunksize] .= ',"k'.$i.'":0';
|
||||
} else {
|
||||
$chunks[$i % $chunksize] = '"k'.$i.'":0';
|
||||
}
|
||||
}
|
||||
$json = '{' . implode(',', $chunks) . '}';
|
||||
var_dump(json_decode($json));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 13
|
||||
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
OOM json_decode() nested objects
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$depth = 1024;
|
||||
$nested = str_repeat('{"o":', $depth) . '{"o":null}' . str_repeat('}', $depth);
|
||||
$elems = '"o0":'.$nested;
|
||||
for ($i = 0; $i < 256; $i++) {
|
||||
$elems .= ',"o'.$i.'":'.$nested;
|
||||
}
|
||||
$json = '{' . $elems . '}';
|
||||
var_dump(json_decode($json, depth: $depth+3));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 10
|
||||
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
OOM json_decode() object as arrays
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$chunks = [];
|
||||
$chunksize = 64;
|
||||
for ($i = 1; $i < 128*1024; $i++) {
|
||||
if (isset($chunks[$i % $chunksize])) {
|
||||
$chunks[$i % $chunksize] .= ',"k'.$i.'":0';
|
||||
} else {
|
||||
$chunks[$i % $chunksize] = '"k'.$i.'":0';
|
||||
}
|
||||
}
|
||||
$json = '{' . implode(',', $chunks) . '}';
|
||||
var_dump(json_decode($json, associative: true));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 13
|
||||
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
OOM json_decode() nested objects as arrays
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$depth = 1024;
|
||||
$nested = str_repeat('{"o":', $depth) . '{"o":null}' . str_repeat('}', $depth);
|
||||
$elems = '"o0":'.$nested;
|
||||
for ($i = 0; $i < 256; $i++) {
|
||||
$elems .= ',"o'.$i.'":'.$nested;
|
||||
}
|
||||
$json = '{' . $elems . '}';
|
||||
var_dump(json_decode($json, associative: true, depth: $depth+3));
|
||||
var_dump(json_last_error_msg());
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 10
|
||||
@@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
OOM json_decode() empty objects
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$elems = '{}'.str_repeat(',{}', 1024*1024);
|
||||
$json = '[' . $elems . ']';
|
||||
var_dump(json_decode($json));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 5
|
||||
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
An OOM left pending by a shutdown function is reported
|
||||
--INI--
|
||||
memory_limit=16M
|
||||
--FILE--
|
||||
<?php
|
||||
register_shutdown_function(function () {
|
||||
echo "Shutdown function called\n";
|
||||
$a = str_repeat('a', 6 * 1024 * 1024);
|
||||
$GLOBALS['b'] = $a . $a;
|
||||
});
|
||||
?>
|
||||
--EXPECTF--
|
||||
Shutdown function called
|
||||
|
||||
Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
OOM range() decreasing float
|
||||
--INI--
|
||||
memory_limit=100M
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_INT_SIZE !== 8) {
|
||||
die('skip 64-bit only');
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(range(100*1024*1024+0.5, 0.5));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
OOM range() increasing float
|
||||
--INI--
|
||||
memory_limit=100M
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_INT_SIZE !== 8) {
|
||||
die('skip 64-bit only');
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(range(0.5, 100*1024*1024+0.5));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
OOM range() decreasing int
|
||||
--INI--
|
||||
memory_limit=100M
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_INT_SIZE !== 8) {
|
||||
die('skip 64-bit only');
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(range(100*1024*1024, 0));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
OOM range() increasing int
|
||||
--INI--
|
||||
memory_limit=100M
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_INT_SIZE !== 8) {
|
||||
die('skip 64-bit only');
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(range(0, 100*1024*1024));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,130 @@
|
||||
--TEST--
|
||||
Request parsing doesn't reach hard limit
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!getenv('TEST_PHP_CGI_EXECUTABLE')) {
|
||||
die("skip php-cgi not available");
|
||||
}
|
||||
if (getenv('SKIP_ASAN')) {
|
||||
die("skip ASan-instrumented realloc() is slow");
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$base = __DIR__ . '/' . basename(__FILE__, '.php');
|
||||
|
||||
$tiny = $base . '.target.php';
|
||||
file_put_contents($tiny, <<<'TARGET'
|
||||
<?php
|
||||
echo "no OOM\n";
|
||||
TARGET);
|
||||
|
||||
$big = $base . '.big.target.php';
|
||||
file_put_contents($big, "<?php\n" . str_repeat("\$x = 1 + 2;\n", 60000) . "echo \"no OOM\\n\";\n");
|
||||
|
||||
/* The body goes through a file rather than a pipe: some of these are several
|
||||
* megabytes, and the child stops reading as soon as it reports the error. */
|
||||
function oom_post(string $body, string $script, array $ini): void
|
||||
{
|
||||
$bodyFile = tempnam(sys_get_temp_dir(), 'oom_request_parsing');
|
||||
file_put_contents($bodyFile, $body);
|
||||
|
||||
$cmd = [getenv('TEST_PHP_CGI_EXECUTABLE'), '-n', '-d', 'fatal_error_backtraces=Off'];
|
||||
foreach ($ini as $entry) {
|
||||
$cmd[] = '-d';
|
||||
$cmd[] = $entry;
|
||||
}
|
||||
|
||||
$p = proc_open(
|
||||
$cmd,
|
||||
[['file', $bodyFile, 'r'], STDOUT, STDERR],
|
||||
$pipes,
|
||||
null,
|
||||
[
|
||||
'REQUEST_METHOD' => 'POST',
|
||||
'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
|
||||
'CONTENT_LENGTH' => (string) strlen($body),
|
||||
'SCRIPT_FILENAME' => $script,
|
||||
'REDIRECT_STATUS' => '1',
|
||||
]
|
||||
);
|
||||
proc_close($p);
|
||||
unlink($bodyFile);
|
||||
}
|
||||
|
||||
/* Deeply nested variable names, at the default max_input_vars and
|
||||
* max_input_nesting_level. */
|
||||
oom_post(
|
||||
implode('&', array_fill(0, 1000, 'a[]' . str_repeat('[b]', 63) . '=c')),
|
||||
$tiny,
|
||||
['memory_limit=8M', 'html_errors=0']
|
||||
);
|
||||
|
||||
$ini = ['memory_limit=8M', 'post_max_size=1G', 'max_input_vars=10000000', 'html_errors=0'];
|
||||
|
||||
/* One value with no '&' in it: nothing consumes it, so add_post_vars() never
|
||||
* gets a complete variable to check and only the read loop can notice. */
|
||||
$oneValue = 'a=' . str_repeat('x', 6 * 1024 * 1024);
|
||||
|
||||
/* Many small variables: the limit is reached while registering them. */
|
||||
$manyVars = '';
|
||||
for ($i = 0; $i < 200000; $i++) {
|
||||
$manyVars .= ($i ? '&' : '') . "k$i=v$i";
|
||||
}
|
||||
|
||||
/* A big value followed by many small ones: add_post_var() copies the value
|
||||
* once with estrndup() and again when registering it, and each half fits even
|
||||
* though the pair doesn't. */
|
||||
$mixed = 'a=' . str_repeat('x', 3 * 1024 * 1024);
|
||||
for ($i = 0; $i < 100000; $i++) {
|
||||
$mixed .= "&k$i=v$i";
|
||||
}
|
||||
|
||||
foreach ([$oneValue, $manyVars, $mixed] as $body) {
|
||||
foreach ([$tiny, $big] as $script) {
|
||||
oom_post($body, $script, $ini);
|
||||
}
|
||||
}
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
$base = __DIR__ . '/' . basename(__FILE__, '.clean.php');
|
||||
@unlink($base . '.target.php');
|
||||
@unlink($base . '.big.target.php');
|
||||
?>
|
||||
--EXPECTF--
|
||||
X-Powered-By: PHP/%s
|
||||
Content-type: text/html; charset=UTF-8
|
||||
|
||||
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
X-Powered-By: PHP/%s
|
||||
Content-type: text/html; charset=UTF-8
|
||||
|
||||
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
X-Powered-By: PHP/%s
|
||||
Content-type: text/html; charset=UTF-8
|
||||
|
||||
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
X-Powered-By: PHP/%s
|
||||
Content-type: text/html; charset=UTF-8
|
||||
|
||||
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
X-Powered-By: PHP/%s
|
||||
Content-type: text/html; charset=UTF-8
|
||||
|
||||
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
X-Powered-By: PHP/%s
|
||||
Content-type: text/html; charset=UTF-8
|
||||
|
||||
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
X-Powered-By: PHP/%s
|
||||
Content-type: text/html; charset=UTF-8
|
||||
|
||||
|
||||
Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
OOM: Soft limit exceeded
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function f() {
|
||||
$a = [];
|
||||
while (true) {
|
||||
$a[] = str_repeat('a', 1024*1024);
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes %s (tried to allocate %d bytes) in %s on line %d
|
||||
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
OOM: Soft limit exceeded in FCALL
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function f() {
|
||||
$a = [];
|
||||
while (true) {
|
||||
array_push($a, str_repeat('a', 1024*1024));
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes %s (tried to allocate %d bytes) in %s on line %d
|
||||
@@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
OOM: Soft limit exceeded in library callback
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function f() {
|
||||
zend_test_emalloc(10*1024*1024);
|
||||
}
|
||||
|
||||
function shutdown_function() {
|
||||
echo "Executed\n";
|
||||
}
|
||||
|
||||
register_shutdown_function('shutdown_function');
|
||||
|
||||
zend_test_callback(function () {
|
||||
f();
|
||||
});
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted %S(tried to allocate %d bytes) in %s on line 4
|
||||
Executed
|
||||
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
OOM str_repeat()
|
||||
--INI--
|
||||
memory_limit=100M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(str_repeat('a', 300<<20));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
OOM unserialize() array
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$chunks = [];
|
||||
$chunksize = 128;
|
||||
for ($i = 0; $i < 2*1024*1024; $i++) {
|
||||
$chunkIdx = (int)($i / $chunksize);
|
||||
$chunks[$chunkIdx] = ($chunks[$chunkIdx] ?? '') . sprintf('i:%d;i:%d;', $i, $i);
|
||||
}
|
||||
$payload = 'a:'.$i.':{'.implode('', $chunks).'}';
|
||||
|
||||
ini_set('memory_limit', '100m');
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 12
|
||||
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
OOM unserialize() array of strings
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$chunks = [];
|
||||
$chunksize = 128;
|
||||
for ($i = 0; $i < 1024*1024; $i++) {
|
||||
$chunkIdx = (int)($i / $chunksize);
|
||||
$str = base_convert($i, 10, 36);
|
||||
$chunks[$chunkIdx] = ($chunks[$chunkIdx] ?? '') . sprintf('i:%d;s:%d:"%s";', $i, strlen($str), $str);
|
||||
}
|
||||
$payload = 'a:'.$i.':{'.implode('', $chunks).'}';
|
||||
|
||||
ini_set('memory_limit', '100m');
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 13
|
||||
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
OOM unserialize() array of string=>int
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$chunks = [];
|
||||
$chunksize = 128;
|
||||
for ($i = 0; $i < 1024*1024; $i++) {
|
||||
$chunkIdx = (int)($i / $chunksize);
|
||||
$str = base_convert($i, 10, 36);
|
||||
$chunks[$chunkIdx] = ($chunks[$chunkIdx] ?? '') . sprintf('s:%d:"%s";i:%d;', strlen($str), $str, $i);
|
||||
}
|
||||
$payload = 'a:'.$i.':{'.implode('', $chunks).'}';
|
||||
|
||||
ini_set('memory_limit', '100m');
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 13
|
||||
@@ -0,0 +1,23 @@
|
||||
--TEST--
|
||||
OOM unserialize() array of old strings
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
error_reporting=E_ALL&~E_DEPRECATED
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$chunks = [];
|
||||
$chunksize = 128;
|
||||
for ($i = 0; $i < 1024*1024; $i++) {
|
||||
$chunkIdx = (int)($i / $chunksize);
|
||||
$str = base_convert($i, 10, 36);
|
||||
$chunks[$chunkIdx] = ($chunks[$chunkIdx] ?? '') . sprintf('i:%d;S:%d:"%s";', $i, strlen($str), $str);
|
||||
}
|
||||
$payload = 'a:'.$i.':{'.implode('', $chunks).'}';
|
||||
|
||||
ini_set('memory_limit', '100m');
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 13
|
||||
@@ -0,0 +1,23 @@
|
||||
--TEST--
|
||||
OOM unserialize() object
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
error_reporting=E_ALL&~E_DEPRECATED
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$chunks = [];
|
||||
$chunksize = 128;
|
||||
for ($i = 0; $i < 1024*1024; $i++) {
|
||||
$chunkIdx = (int)($i / $chunksize);
|
||||
$prop = sprintf('p%d', $i);
|
||||
$chunks[$chunkIdx] = ($chunks[$chunkIdx] ?? '') . sprintf('s:%d:"%s";i:%d;', strlen($prop), $prop, $i);
|
||||
}
|
||||
$payload = 'O:8:"stdClass":'.$i.':{'.implode('', $chunks).'}';
|
||||
|
||||
ini_set('memory_limit', '100m');
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 13
|
||||
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
OOM unserialize() object of int=>int
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
error_reporting=E_ALL&~E_DEPRECATED
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$chunks = [];
|
||||
$chunksize = 128;
|
||||
for ($i = 0; $i < 1024*1024; $i++) {
|
||||
$chunkIdx = (int)($i / $chunksize);
|
||||
$chunks[$chunkIdx] = ($chunks[$chunkIdx] ?? '') . sprintf('i:%d;i:%d;', $i, $i);
|
||||
}
|
||||
$payload = 'O:8:"stdClass":'.$i.':{'.implode('', $chunks).'}';
|
||||
|
||||
ini_set('memory_limit', '64m');
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 67108864 bytes exhausted %S(tried to allocate %d bytes) in %s on line 12
|
||||
@@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
OOM unserialize() classname
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
error_reporting=E_ALL&~E_DEPRECATED
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$classname = str_repeat('a', 32*1024*1024);
|
||||
$payload = 'O:'.strlen($classname).':"'.$classname.'":0:{}';
|
||||
|
||||
ini_set('memory_limit', memory_get_usage() + 20*1024*1024);
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of %d bytes exhausted %S(tried to allocate %d bytes) in %s on line 7
|
||||
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
OOM unserialize() classname (2)
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
error_reporting=E_ALL&~E_DEPRECATED
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
// Use a classname with uppercase chars, so a lowercase copy is needed. We OOM
|
||||
// while creating the copy.
|
||||
$classname = str_repeat('A', 32*1024*1024);
|
||||
$payload = 'O:'.strlen($classname).':"'.$classname.'":0:{}';
|
||||
|
||||
ini_set('memory_limit', memory_get_usage() + 40*1024*1024);
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of %d bytes exhausted %S(tried to allocate %d bytes) in %s on line 9
|
||||
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
OOM unserialize() Serializable
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
error_reporting=E_ALL&~E_DEPRECATED
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class C implements Serializable
|
||||
{
|
||||
public $data;
|
||||
public function serialize(): ?string {
|
||||
return 'hello';
|
||||
}
|
||||
public function unserialize(string $data): void {
|
||||
str_repeat('a', 200<<20);
|
||||
}
|
||||
}
|
||||
|
||||
$payload = 'C:1:"C":5:{hello}';
|
||||
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of %d bytes exhausted %S(tried to allocate %d bytes) in %s on line 10
|
||||
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
OOM unserialize() array of objects
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$chunks = [];
|
||||
$chunksize = 128;
|
||||
for ($i = 0; $i < 512*1024; $i++) {
|
||||
$chunkIdx = (int)($i / $chunksize);
|
||||
$str = base_convert($i, 10, 36);
|
||||
$chunks[$chunkIdx] = ($chunks[$chunkIdx] ?? '') . sprintf('i:%d;O:8:"stdClass":0:{}', $i);
|
||||
}
|
||||
$payload = 'a:'.$i.':{'.implode('', $chunks).'}';
|
||||
|
||||
ini_set('memory_limit', '64m');
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 67108864 bytes exhausted %S(tried to allocate %d bytes) in %s on line 13
|
||||
@@ -0,0 +1,23 @@
|
||||
--TEST--
|
||||
OOM unserialize() object fextend
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$chunks = [];
|
||||
$chunksize = 128;
|
||||
for ($i = 0; $i < 2*1024*1024; $i++) {
|
||||
$chunkIdx = (int)($i / $chunksize);
|
||||
$prop = sprintf('p%d', $i);
|
||||
$chunks[$chunkIdx] = ($chunks[$chunkIdx] ?? '') . sprintf('s:%d:"%s";i:%d;', strlen($prop), $prop, $i);
|
||||
}
|
||||
$payload = 'O:8:"stdClass":'.$i.':{'.implode('', $chunks).'}';
|
||||
$chunks = null;
|
||||
|
||||
ini_set('memory_limit', '100m');
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 14
|
||||
@@ -0,0 +1,28 @@
|
||||
--TEST--
|
||||
OOM unserialize() object __wakeup
|
||||
--INI--
|
||||
memory_limit=100M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class C {
|
||||
public function __wakeup() {
|
||||
str_repeat('a', 200*1024*1024);
|
||||
}
|
||||
}
|
||||
|
||||
class D {
|
||||
public function __wakeup() {
|
||||
echo "Not executed";
|
||||
// Would hit hard limit
|
||||
zend_test_emalloc(200*1024*1024);
|
||||
}
|
||||
}
|
||||
|
||||
$payload = 'a:2:{i:0;O:1:"C":0:{}i:1;O:1:"D":0:{}}';
|
||||
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 5
|
||||
@@ -0,0 +1,28 @@
|
||||
--TEST--
|
||||
OOM unserialize() object __unserialize (2)
|
||||
--INI--
|
||||
memory_limit=200M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class C {
|
||||
public function __unserialize($data) {
|
||||
}
|
||||
}
|
||||
|
||||
$chunks = [];
|
||||
$chunksize = 128;
|
||||
for ($i = 0; $i < 1024*1024; $i++) {
|
||||
$chunkIdx = (int)($i / $chunksize);
|
||||
$prop = sprintf('p%d', $i);
|
||||
$chunks[$chunkIdx] = ($chunks[$chunkIdx] ?? '') . sprintf('s:%d:"%s";i:%d;', strlen($prop), $prop, $i);
|
||||
}
|
||||
$payload = 'O:1:"C":'.$i.':{'.implode('', $chunks).'}';
|
||||
$chunks = null;
|
||||
|
||||
ini_set('memory_limit', '100m');
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 19
|
||||
@@ -0,0 +1,20 @@
|
||||
--TEST--
|
||||
OOM unserialize() object __unserialize (2)
|
||||
--INI--
|
||||
memory_limit=100M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class C {
|
||||
public function __unserialize($data) {
|
||||
str_repeat('a', 200<<20);
|
||||
}
|
||||
}
|
||||
|
||||
$payload = 'O:1:"C":0:{}';
|
||||
|
||||
var_dump(gettype(unserialize($payload)));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %S(tried to allocate %d bytes) in %s on line 5
|
||||
@@ -0,0 +1,33 @@
|
||||
--TEST--
|
||||
OOM unserialize() cleans up BG(unserialize) after a delayed OOM
|
||||
--INI--
|
||||
memory_limit=8M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
register_shutdown_function(function () {
|
||||
/* Runs after the fatal error. If the var_hash of the failed call were
|
||||
* still installed, this call would nest into it and R:1 would resolve
|
||||
* into that call's table instead of this array. */
|
||||
var_dump(unserialize('a:1:{i:0;R:1;}'));
|
||||
});
|
||||
|
||||
/* 40000 one-element arrays: ~760 KB serialized, ~10 MB unserialized. */
|
||||
$n = 40000;
|
||||
$ser = 'a:' . $n . ':{';
|
||||
for ($i = 0; $i < $n; $i++) {
|
||||
$ser .= 'i:' . $i . ';a:1:{i:0;i:0;}';
|
||||
}
|
||||
$ser .= '}';
|
||||
|
||||
unserialize($ser);
|
||||
|
||||
echo "not reached\n";
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of %d bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
array(1) {
|
||||
[0]=>
|
||||
*RECURSION*
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
--TEST--
|
||||
array_init_singleton()
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = zend_new_singleton_array();
|
||||
var_dump($a, count($a));
|
||||
|
||||
/* Stays packed while growing: 1 -> 2 -> 4 -> 8 -> 16 */
|
||||
$a = zend_new_singleton_array();
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$a[] = $i;
|
||||
}
|
||||
var_dump($a === range(0, 9));
|
||||
|
||||
/* First insert is a string key: goes straight to a mixed table of size 1,
|
||||
* whose hash area is only 2 slots wide. */
|
||||
$a = zend_new_singleton_array();
|
||||
$a['foo'] = 1;
|
||||
$a['bar'] = 2;
|
||||
$a['baz'] = 3;
|
||||
var_dump($a);
|
||||
|
||||
/* Packed -> hash conversion of a size 1 table. */
|
||||
$a = zend_new_singleton_array();
|
||||
$a[] = 'first';
|
||||
$a['key'] = 'second';
|
||||
var_dump($a);
|
||||
|
||||
/* An out of range integer key also skips the packed representation. */
|
||||
$a = zend_new_singleton_array();
|
||||
$a[100] = 'hundred';
|
||||
$a[0] = 'zero';
|
||||
var_dump($a);
|
||||
|
||||
/* Deletion, rehashing and reuse. */
|
||||
$a = zend_new_singleton_array();
|
||||
$a['a'] = 1;
|
||||
$a['b'] = 2;
|
||||
unset($a['a']);
|
||||
$a['c'] = 3;
|
||||
unset($a['b']);
|
||||
$a['d'] = 4;
|
||||
var_dump($a);
|
||||
|
||||
/* Separation (zend_array_dup) of a size 1 table. */
|
||||
$a = zend_new_singleton_array();
|
||||
$a['x'] = 1;
|
||||
$b = $a;
|
||||
$b['y'] = 2;
|
||||
var_dump($a, $b);
|
||||
|
||||
/* Sorting and renumbering. */
|
||||
$a = zend_new_singleton_array();
|
||||
$a['c'] = 3;
|
||||
$a['a'] = 1;
|
||||
$a['b'] = 2;
|
||||
asort($a);
|
||||
var_dump($a);
|
||||
sort($a);
|
||||
var_dump($a);
|
||||
|
||||
/* Round-trips. */
|
||||
$a = zend_new_singleton_array();
|
||||
$a['only'] = 'one';
|
||||
var_dump(unserialize(serialize($a)) === $a);
|
||||
var_dump(json_decode(json_encode($a), true) === $a);
|
||||
|
||||
/* Iteration. */
|
||||
$a = zend_new_singleton_array();
|
||||
$a[] = 'a';
|
||||
$a[] = 'b';
|
||||
foreach ($a as $k => $v) {
|
||||
echo "$k => $v\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(0) {
|
||||
}
|
||||
int(0)
|
||||
bool(true)
|
||||
array(3) {
|
||||
["foo"]=>
|
||||
int(1)
|
||||
["bar"]=>
|
||||
int(2)
|
||||
["baz"]=>
|
||||
int(3)
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(5) "first"
|
||||
["key"]=>
|
||||
string(6) "second"
|
||||
}
|
||||
array(2) {
|
||||
[100]=>
|
||||
string(7) "hundred"
|
||||
[0]=>
|
||||
string(4) "zero"
|
||||
}
|
||||
array(2) {
|
||||
["c"]=>
|
||||
int(3)
|
||||
["d"]=>
|
||||
int(4)
|
||||
}
|
||||
array(1) {
|
||||
["x"]=>
|
||||
int(1)
|
||||
}
|
||||
array(2) {
|
||||
["x"]=>
|
||||
int(1)
|
||||
["y"]=>
|
||||
int(2)
|
||||
}
|
||||
array(3) {
|
||||
["a"]=>
|
||||
int(1)
|
||||
["b"]=>
|
||||
int(2)
|
||||
["c"]=>
|
||||
int(3)
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
bool(true)
|
||||
bool(true)
|
||||
0 => a
|
||||
1 => b
|
||||
+9
-1
@@ -756,6 +756,8 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{
|
||||
memset(base, 0, (zend_map_ptr_static_size + compiler_globals->map_ptr_last) * sizeof(void*));
|
||||
}
|
||||
zend_init_internal_run_time_cache();
|
||||
|
||||
compiler_globals->interned_strings_fallible = false;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -854,6 +856,7 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{
|
||||
sizeof(executor_globals->strtod_state.freelist));
|
||||
executor_globals->strtod_state.p5s = NULL;
|
||||
executor_globals->strtod_state.result = NULL;
|
||||
memset(&executor_globals->delayed_oom, 0, sizeof(executor_globals->delayed_oom));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -1401,6 +1404,8 @@ ZEND_API void zend_deactivate(void) /* {{{ */
|
||||
zend_map_ptr_reset();
|
||||
}
|
||||
|
||||
zend_mm_oom_info_dtor(&EG(delayed_oom));
|
||||
|
||||
#if GC_BENCH
|
||||
gc_bench_print();
|
||||
#endif
|
||||
@@ -1511,7 +1516,7 @@ ZEND_API ZEND_COLD void zend_error_zstr_at(
|
||||
ZVAL_UNDEF(&EG(last_fatal_error_backtrace));
|
||||
|
||||
/* Report about uncaught exception in case of fatal errors */
|
||||
if (EG(exception)) {
|
||||
if (EG(exception) && EXPECTED(EG(delayed_oom).state != ZEND_OOM_STATE_HANDLING)) {
|
||||
if (type & E_FATAL_ERRORS) {
|
||||
zend_execute_data *ex = EG(current_execute_data);
|
||||
const zend_op *opline = NULL;
|
||||
@@ -1979,6 +1984,9 @@ ZEND_API zend_result zend_execute_script(int type, zval *retval, zend_file_handl
|
||||
zend_result ret = SUCCESS;
|
||||
if (op_array) {
|
||||
zend_execute(op_array, retval);
|
||||
if (ZEND_HAS_OOM()) {
|
||||
zend_handle_delayed_oom();
|
||||
}
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
|
||||
zend_user_exception_handler();
|
||||
|
||||
@@ -1998,6 +1998,18 @@ ZEND_API void object_init(zval *arg) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API bool object_finit(zval *arg)
|
||||
{
|
||||
zend_object *obj = zend_objects_fnew(zend_standard_class_def);
|
||||
|
||||
if (UNEXPECTED(obj == NULL)) {
|
||||
ZVAL_NULL(arg);
|
||||
return false;
|
||||
}
|
||||
ZVAL_OBJ(arg, obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
ZEND_API void add_assoc_long_ex(zval *arg, const char *key, size_t key_len, zend_long n) /* {{{ */
|
||||
{
|
||||
zval tmp;
|
||||
|
||||
@@ -549,7 +549,67 @@ static zend_always_inline void array_init(zval *arg)
|
||||
array_init_size(arg, 0);
|
||||
}
|
||||
|
||||
static zend_always_inline void array_init_singleton(zval *arg)
|
||||
{
|
||||
ZVAL_ARR(arg, zend_new_array_singleton());
|
||||
}
|
||||
|
||||
/* Fallible array_init()/object_init(): on failure return false and leave arg as
|
||||
* IS_NULL, so arg stays safe to destroy. */
|
||||
static zend_always_inline bool _array_finit(zval *arg, size_t size)
|
||||
{
|
||||
zend_array *ht = zend_fnew_array(size);
|
||||
if (UNEXPECTED(ht == NULL)) {
|
||||
ZVAL_NULL(arg);
|
||||
return false;
|
||||
}
|
||||
ZVAL_ARR(arg, ht);
|
||||
return true;
|
||||
}
|
||||
|
||||
static zend_always_inline bool _array_finit_ex(zval *arg, size_t size, bool packed)
|
||||
{
|
||||
zend_array *ht = zend_fnew_array(size);
|
||||
if (UNEXPECTED(ht == NULL)) {
|
||||
ZVAL_NULL(arg);
|
||||
return false;
|
||||
}
|
||||
if (UNEXPECTED(zend_hash_real_finit(ht, packed, /* fallible */ true) == FAILURE)) {
|
||||
efree(ht);
|
||||
ZVAL_NULL(arg);
|
||||
return false;
|
||||
}
|
||||
ZVAL_ARR(arg, ht);
|
||||
return true;
|
||||
}
|
||||
|
||||
static zend_always_inline bool array_finit(zval *arg)
|
||||
{
|
||||
return _array_finit(arg, 0);
|
||||
}
|
||||
|
||||
static zend_always_inline bool array_finit_size(zval *arg, size_t size)
|
||||
{
|
||||
return _array_finit(arg, size);
|
||||
}
|
||||
|
||||
static zend_always_inline bool array_finit_size_ex(zval *arg, size_t size, bool packed)
|
||||
{
|
||||
return _array_finit_ex(arg, size, packed);
|
||||
}
|
||||
|
||||
static zend_always_inline bool array_finit_size_packed(zval *arg, size_t size)
|
||||
{
|
||||
return _array_finit_ex(arg, size, /* packed */ true);
|
||||
}
|
||||
|
||||
static zend_always_inline bool array_finit_size_mixed(zval *arg, size_t size)
|
||||
{
|
||||
return _array_finit_ex(arg, size, /* packed */ false);
|
||||
}
|
||||
|
||||
ZEND_API void object_init(zval *arg);
|
||||
ZEND_API bool object_finit(zval *arg);
|
||||
ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *ce);
|
||||
ZEND_API zend_result object_init_with_constructor(zval *arg, zend_class_entry *class_type, uint32_t param_count, zval *params, HashTable *named_params);
|
||||
ZEND_API zend_result object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties);
|
||||
@@ -989,11 +1049,26 @@ static zend_always_inline bool zend_char_has_nul_byte(const char *s, size_t know
|
||||
ZVAL_NEW_STR(z, zend_string_init(s, l, 0)); \
|
||||
} while (0)
|
||||
|
||||
/* Fallible variant of ZVAL_STRINGL() to be used when 's' is not managed by zend_alloc */
|
||||
static zend_always_inline bool ZVAL_FSTRINGL(zval *z, const char *s, size_t l) {
|
||||
zend_string *str = zend_string_finit(s, l, /* persistent */ false, /* fallible */ true);
|
||||
if (UNEXPECTED(!str)) {
|
||||
ZVAL_INTERNED_STR(z, ZSTR_EMPTY_ALLOC());
|
||||
return false;
|
||||
}
|
||||
ZVAL_NEW_STR(z, str);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define ZVAL_STRING(z, s) do { \
|
||||
const char *_s = (s); \
|
||||
ZVAL_STRINGL(z, _s, strlen(_s)); \
|
||||
} while (0)
|
||||
|
||||
static zend_always_inline bool ZVAL_FSTRING(zval *z, const char *s) {
|
||||
return ZVAL_FSTRINGL(z, s, strlen(s));
|
||||
}
|
||||
|
||||
#define ZVAL_EMPTY_STRING(z) do { \
|
||||
ZVAL_INTERNED_STR(z, ZSTR_EMPTY_ALLOC()); \
|
||||
} while (0)
|
||||
@@ -1054,6 +1129,8 @@ static zend_always_inline bool zend_char_has_nul_byte(const char *s, size_t know
|
||||
#define RETVAL_STRINGL(s, l) ZVAL_STRINGL(return_value, s, l)
|
||||
#define RETVAL_STRING_FAST(s) ZVAL_STRING_FAST(return_value, s)
|
||||
#define RETVAL_STRINGL_FAST(s, l) ZVAL_STRINGL_FAST(return_value, s, l)
|
||||
#define RETVAL_FSTRING(s) ZVAL_FSTRING(return_value, s)
|
||||
#define RETVAL_FSTRINGL(s, l) ZVAL_FSTRINGL(return_value, s, l)
|
||||
#define RETVAL_EMPTY_STRING() ZVAL_EMPTY_STRING(return_value)
|
||||
#define RETVAL_CHAR(c) ZVAL_CHAR(return_value, c)
|
||||
#define RETVAL_RES(r) ZVAL_RES(return_value, r)
|
||||
@@ -1080,6 +1157,8 @@ static zend_always_inline bool zend_char_has_nul_byte(const char *s, size_t know
|
||||
#define RETURN_STRINGL(s, l) do { RETVAL_STRINGL(s, l); return; } while (0)
|
||||
#define RETURN_STRING_FAST(s) do { RETVAL_STRING_FAST(s); return; } while (0)
|
||||
#define RETURN_STRINGL_FAST(s, l) do { RETVAL_STRINGL_FAST(s, l); return; } while (0)
|
||||
#define RETURN_FSTRING(s) do { RETVAL_FSTRING(s); return; } while (0)
|
||||
#define RETURN_FSTRINGL(s, l) do { RETVAL_FSTRINGL(s, l); return; } while (0)
|
||||
#define RETURN_EMPTY_STRING() do { RETVAL_EMPTY_STRING(); return; } while (0)
|
||||
#define RETURN_CHAR(c) do { RETVAL_CHAR(c); return; } while (0)
|
||||
#define RETURN_RES(r) do { RETVAL_RES(r); return; } while (0)
|
||||
@@ -1094,6 +1173,7 @@ static zend_always_inline bool zend_char_has_nul_byte(const char *s, size_t know
|
||||
#define RETURN_FALSE do { RETVAL_FALSE; return; } while (0)
|
||||
#define RETURN_TRUE do { RETVAL_TRUE; return; } while (0)
|
||||
#define RETURN_THROWS() do { ZEND_ASSERT(EG(exception)); (void) return_value; return; } while (0)
|
||||
#define RETURN_OOM() do { ZEND_ASSERT(ZEND_HAS_OOM()); (void) return_value; return; } while (0)
|
||||
|
||||
#define HASH_OF(p) (Z_TYPE_P(p)==IS_ARRAY ? Z_ARRVAL_P(p) : ((Z_TYPE_P(p)==IS_OBJECT ? Z_OBJ_HT_P(p)->get_properties(Z_OBJ_P(p)) : NULL)))
|
||||
|
||||
|
||||
+529
-126
@@ -52,6 +52,7 @@
|
||||
|
||||
#include "zend.h"
|
||||
#include "zend_alloc.h"
|
||||
#include "zend_API.h"
|
||||
#include "zend_globals.h"
|
||||
#include "zend_hrtime.h"
|
||||
#include "zend_operators.h"
|
||||
@@ -59,6 +60,8 @@
|
||||
#include "zend_bitset.h"
|
||||
#include "zend_mmap.h"
|
||||
#include "zend_portability.h"
|
||||
#include "zend_string.h"
|
||||
#include "zend_exceptions.h"
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
@@ -216,6 +219,10 @@ typedef zend_mm_bitset zend_mm_page_map[ZEND_MM_PAGE_MAP_LEN]; /* 64B */
|
||||
|
||||
#define ZEND_MM_BINS 30
|
||||
|
||||
#if ZEND_MM_LIMIT
|
||||
# define ZEND_MM_LIMIT_MAX ((size_t)Z_L(-1) >> 1)
|
||||
#endif
|
||||
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
# define BSWAPPTR(u) ZEND_BYTES_SWAP64(u)
|
||||
#else
|
||||
@@ -229,6 +236,7 @@ typedef struct _zend_mm_chunk zend_mm_chunk;
|
||||
typedef struct _zend_mm_huge_list zend_mm_huge_list;
|
||||
|
||||
static bool zend_mm_use_huge_pages = false;
|
||||
static bool zend_mm_max_allocs_reached = false;
|
||||
|
||||
/*
|
||||
* Memory is retrieved from OS by chunks of fixed size 2MB.
|
||||
@@ -283,8 +291,11 @@ struct _zend_mm_heap {
|
||||
#endif
|
||||
#if ZEND_MM_LIMIT
|
||||
size_t limit; /* memory limit */
|
||||
size_t hard_limit;
|
||||
zend_long hard_limit_percent;
|
||||
int overflow; /* memory overflow flag */
|
||||
#endif
|
||||
bool fallible;
|
||||
|
||||
zend_mm_huge_list *huge_list; /* list of huge allocated blocks */
|
||||
|
||||
@@ -315,6 +326,7 @@ struct _zend_mm_heap {
|
||||
bool check_freelists_on_shutdown;
|
||||
} debug;
|
||||
};
|
||||
uint64_t max_allocs;
|
||||
#endif
|
||||
#if ZEND_DEBUG
|
||||
pid_t pid;
|
||||
@@ -393,31 +405,160 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message)
|
||||
abort();
|
||||
}
|
||||
|
||||
static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap,
|
||||
const char *format,
|
||||
size_t limit,
|
||||
#if ZEND_DEBUG
|
||||
const char *filename,
|
||||
uint32_t lineno,
|
||||
#endif
|
||||
size_t size)
|
||||
{
|
||||
static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void);
|
||||
|
||||
heap->overflow = 1;
|
||||
zend_try {
|
||||
zend_error_noreturn(E_ERROR,
|
||||
format,
|
||||
limit,
|
||||
#if ZEND_DEBUG
|
||||
filename,
|
||||
lineno,
|
||||
#endif
|
||||
size);
|
||||
} zend_catch {
|
||||
} zend_end_try();
|
||||
heap->overflow = 0;
|
||||
zend_bailout();
|
||||
exit(1);
|
||||
static ZEND_COLD void zend_mm_delayed_verror(const char *format, va_list args)
|
||||
{
|
||||
if (ZEND_HAS_OOM()) {
|
||||
return;
|
||||
}
|
||||
|
||||
zend_string *script_filename = NULL;
|
||||
uint32_t script_lineno = 0;
|
||||
|
||||
if (zend_is_executing()) {
|
||||
script_filename = zend_get_executed_filename_ex();
|
||||
script_lineno = zend_get_executed_lineno();
|
||||
} else if (zend_is_compiling()) {
|
||||
script_filename = zend_get_compiled_filename();
|
||||
script_lineno = zend_get_compiled_lineno();
|
||||
}
|
||||
|
||||
if (script_filename == NULL) {
|
||||
script_filename = ZSTR_KNOWN(ZEND_STR_UNKNOWN_CAPITALIZED);
|
||||
script_lineno = 0;
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
vsnprintf(buf, sizeof(buf), format, args);
|
||||
|
||||
EG(delayed_oom).message = zend_string_init(buf, strlen(buf), /* persistent */ true);
|
||||
GC_MAKE_PERSISTENT_LOCAL(EG(delayed_oom).message);
|
||||
zend_string_addref(script_filename);
|
||||
EG(delayed_oom).filename = script_filename;
|
||||
EG(delayed_oom).lineno = script_lineno;
|
||||
EG(delayed_oom).state = ZEND_OOM_STATE_PENDING;
|
||||
|
||||
zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
|
||||
}
|
||||
|
||||
ZEND_ATTRIBUTE_FORMAT(printf, 1, 2)
|
||||
static ZEND_COLD void zend_mm_delayed_error(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
zend_mm_delayed_verror(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
ZEND_ATTRIBUTE_FORMAT(printf, 2, 3)
|
||||
ZEND_API ZEND_COLD void zend_mm_delayed_error_or_panic(bool delay, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
if (delay) {
|
||||
zend_mm_delayed_verror(format, args);
|
||||
} else {
|
||||
char buf[1024];
|
||||
vsnprintf(buf, sizeof(buf), format, args);
|
||||
zend_mm_panic(buf);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
ZEND_COLD void zend_mm_oom_info_dtor(zend_oom_info *info)
|
||||
{
|
||||
if (info->message) {
|
||||
zend_string_release(info->message);
|
||||
info->message = NULL;
|
||||
}
|
||||
if (info->filename) {
|
||||
zend_string_release(info->filename);
|
||||
info->filename = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ZEND_MM_LIMIT
|
||||
static ZEND_COLD ZEND_NORETURN void zend_mm_hard_limit_error(zend_mm_heap *heap,
|
||||
size_t add_size ZEND_FILE_LINE_DC)
|
||||
{
|
||||
zend_string *script_filename = NULL;
|
||||
uint32_t script_lineno = 0;
|
||||
|
||||
if (zend_is_executing()) {
|
||||
script_filename = zend_get_executed_filename_ex();
|
||||
script_lineno = zend_get_executed_lineno();
|
||||
} else if (zend_is_compiling()) {
|
||||
script_filename = zend_get_compiled_filename();
|
||||
script_lineno = zend_get_compiled_lineno();
|
||||
}
|
||||
|
||||
if (script_filename == NULL) {
|
||||
script_filename = ZSTR_KNOWN(ZEND_STR_UNKNOWN_CAPITALIZED);
|
||||
script_lineno = 0;
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
# if ZEND_DEBUG
|
||||
"Hard memory limit of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes) in %s on line %d\n",
|
||||
# else
|
||||
"Hard memory limit of %zu bytes exhausted (tried to allocate %zu bytes) in %s on line %d\n",
|
||||
# endif
|
||||
heap->hard_limit
|
||||
ZEND_FILE_LINE_RELAY_CC,
|
||||
add_size,
|
||||
ZSTR_VAL(script_filename),
|
||||
script_lineno);
|
||||
|
||||
/* See http://support.microsoft.com/kb/190351 */
|
||||
# ifdef ZEND_WIN32
|
||||
fflush(stderr);
|
||||
# endif
|
||||
|
||||
_exit(137);
|
||||
}
|
||||
#endif /* ZEND_MM_LIMIT */
|
||||
|
||||
/* Returns FAILURE if allocation should fail (in case the heap is fallible).
|
||||
* When the soft limit is to be exceeded, a delayed OOM error is queued.
|
||||
* When the hard limit is to be exceeded, the function does not return.
|
||||
*/
|
||||
static zend_always_inline zend_result zend_mm_check_limit(zend_mm_heap *heap, size_t add_size, bool gc, bool *did_gc ZEND_FILE_LINE_DC)
|
||||
{
|
||||
#if ZEND_MM_LIMIT
|
||||
/* Is the soft limit exceeded or going to be exceeded? */
|
||||
if (UNEXPECTED(heap->limit < heap->real_size || add_size > heap->limit - heap->real_size)) {
|
||||
if (gc && zend_mm_gc(heap)) {
|
||||
if (did_gc) {
|
||||
*did_gc = true;
|
||||
}
|
||||
}
|
||||
ZEND_ASSERT(heap->hard_limit >= heap->limit && heap->hard_limit >= heap->real_size);
|
||||
if (!heap->fallible && add_size > heap->hard_limit - heap->real_size) {
|
||||
zend_mm_hard_limit_error(heap, add_size ZEND_FILE_LINE_RELAY_CC);
|
||||
}
|
||||
/* Check soft limit again as gc may have reduced memory usage */
|
||||
if (!gc || (heap->limit < heap->real_size || add_size > heap->limit - heap->real_size)) {
|
||||
if (!ZEND_HAS_OOM()) {
|
||||
zend_mm_delayed_error(
|
||||
# if ZEND_DEBUG
|
||||
"Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)",
|
||||
# else
|
||||
"Allowed memory size of %zu bytes exhausted (tried to allocate %zu bytes)",
|
||||
# endif
|
||||
heap->limit
|
||||
ZEND_FILE_LINE_RELAY_CC,
|
||||
add_size);
|
||||
}
|
||||
|
||||
return heap->fallible ? FAILURE : SUCCESS;
|
||||
}
|
||||
}
|
||||
#endif /* ZEND_MM_LIMIT */
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -1095,20 +1236,13 @@ get_chunk:
|
||||
ZEND_MM_CHECK(ZEND_MM_ALIGNED_OFFSET(chunk, ZEND_MM_CHUNK_SIZE) == 0, "zend_mm_heap corrupted");
|
||||
heap->cached_chunks = zend_mm_get_next_cached_chunk(heap, chunk);
|
||||
} else {
|
||||
#if ZEND_MM_LIMIT
|
||||
if (UNEXPECTED(ZEND_MM_CHUNK_SIZE > heap->limit - heap->real_size)) {
|
||||
if (zend_mm_gc(heap)) {
|
||||
goto get_chunk;
|
||||
} else if (heap->overflow == 0) {
|
||||
#if ZEND_DEBUG
|
||||
zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)", heap->limit, __zend_filename, __zend_lineno, size);
|
||||
#else
|
||||
zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted (tried to allocate %zu bytes)", heap->limit, ZEND_MM_PAGE_SIZE * pages_count);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
bool did_gc = false;
|
||||
if (UNEXPECTED(zend_mm_check_limit(heap, ZEND_MM_CHUNK_SIZE, /* gc */ true, &did_gc ZEND_FILE_LINE_RELAY_CC) == FAILURE)) {
|
||||
return NULL;
|
||||
} else if (did_gc) {
|
||||
goto get_chunk;
|
||||
}
|
||||
#endif
|
||||
|
||||
chunk = (zend_mm_chunk*)zend_mm_chunk_alloc(heap, ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE);
|
||||
if (UNEXPECTED(chunk == NULL)) {
|
||||
/* insufficient memory */
|
||||
@@ -1116,13 +1250,7 @@ get_chunk:
|
||||
(chunk = (zend_mm_chunk*)zend_mm_chunk_alloc(heap, ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE)) != NULL) {
|
||||
/* pass */
|
||||
} else {
|
||||
#if !ZEND_MM_LIMIT
|
||||
zend_mm_safe_error(heap, "Out of memory");
|
||||
#elif ZEND_DEBUG
|
||||
zend_mm_safe_error(heap, "Out of memory (allocated %zu bytes) at %s:%d (tried to allocate %zu bytes)", heap->real_size, __zend_filename, __zend_lineno, size);
|
||||
#else
|
||||
zend_mm_safe_error(heap, "Out of memory (allocated %zu bytes) (tried to allocate %zu bytes)", heap->real_size, ZEND_MM_PAGE_SIZE * pages_count);
|
||||
#endif
|
||||
zend_out_of_memory();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -1183,6 +1311,9 @@ static zend_always_inline void *zend_mm_alloc_large_ex(zend_mm_heap *heap, size_
|
||||
#else
|
||||
void *ptr = zend_mm_alloc_pages(heap, pages_count ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
#endif
|
||||
if (UNEXPECTED(ptr == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
#if ZEND_MM_STAT
|
||||
do {
|
||||
size_t size = heap->size + pages_count * ZEND_MM_PAGE_SIZE;
|
||||
@@ -1415,6 +1546,11 @@ static zend_never_inline void *zend_mm_alloc_small_slow(zend_mm_heap *heap, uint
|
||||
#endif
|
||||
if (UNEXPECTED(bin == NULL)) {
|
||||
/* insufficient memory */
|
||||
#if ZEND_MM_STAT
|
||||
/* heap->size was incremented by the caller. Decrement here to preserve
|
||||
* the tail call. */
|
||||
heap->size -= bin_data_size[bin_num];
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1551,29 +1687,34 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si
|
||||
size = MAX(size, 1);
|
||||
size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info));
|
||||
if (UNEXPECTED(size < real_size)) {
|
||||
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)));
|
||||
zend_mm_delayed_error_or_panic(heap->fallible, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)));
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
if (EXPECTED(size <= ZEND_MM_MAX_SMALL_SIZE)) {
|
||||
ptr = zend_mm_alloc_small(heap, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
#if ZEND_DEBUG
|
||||
dbg = zend_mm_get_debug_info(heap, ptr);
|
||||
dbg->size = real_size;
|
||||
dbg->filename = __zend_filename;
|
||||
dbg->orig_filename = __zend_orig_filename;
|
||||
dbg->lineno = __zend_lineno;
|
||||
dbg->orig_lineno = __zend_orig_lineno;
|
||||
if (EXPECTED(ptr != NULL)) {
|
||||
dbg = zend_mm_get_debug_info(heap, ptr);
|
||||
dbg->size = real_size;
|
||||
dbg->filename = __zend_filename;
|
||||
dbg->orig_filename = __zend_orig_filename;
|
||||
dbg->lineno = __zend_lineno;
|
||||
dbg->orig_lineno = __zend_orig_lineno;
|
||||
}
|
||||
#endif
|
||||
return ptr;
|
||||
} else if (EXPECTED(size <= ZEND_MM_MAX_LARGE_SIZE)) {
|
||||
ptr = zend_mm_alloc_large(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
#if ZEND_DEBUG
|
||||
dbg = zend_mm_get_debug_info(heap, ptr);
|
||||
dbg->size = real_size;
|
||||
dbg->filename = __zend_filename;
|
||||
dbg->orig_filename = __zend_orig_filename;
|
||||
dbg->lineno = __zend_lineno;
|
||||
dbg->orig_lineno = __zend_orig_lineno;
|
||||
if (EXPECTED(ptr != NULL)) {
|
||||
dbg = zend_mm_get_debug_info(heap, ptr);
|
||||
dbg->size = real_size;
|
||||
dbg->filename = __zend_filename;
|
||||
dbg->orig_filename = __zend_orig_filename;
|
||||
dbg->lineno = __zend_lineno;
|
||||
dbg->orig_lineno = __zend_orig_lineno;
|
||||
}
|
||||
#endif
|
||||
return ptr;
|
||||
} else {
|
||||
@@ -1649,10 +1790,16 @@ static zend_never_inline void *zend_mm_realloc_slow(zend_mm_heap *heap, void *pt
|
||||
size_t orig_peak = heap->peak;
|
||||
#endif
|
||||
ret = zend_mm_alloc_heap(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
memcpy(ret, ptr, copy_size);
|
||||
zend_mm_free_heap(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
if (EXPECTED(ret != NULL)) {
|
||||
memcpy(ret, ptr, copy_size);
|
||||
zend_mm_free_heap(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
} else {
|
||||
/* original block is left untouched */
|
||||
}
|
||||
#if ZEND_MM_STAT
|
||||
heap->peak = MAX(orig_peak, heap->size);
|
||||
if (EXPECTED(ret != NULL)) {
|
||||
heap->peak = MAX(orig_peak, heap->size);
|
||||
}
|
||||
} while (0);
|
||||
#endif
|
||||
return ret;
|
||||
@@ -1708,20 +1855,10 @@ static zend_never_inline void *zend_mm_realloc_huge(zend_mm_heap *heap, void *pt
|
||||
return ptr;
|
||||
}
|
||||
} else /* if (new_size > old_size) */ {
|
||||
#if ZEND_MM_LIMIT
|
||||
if (UNEXPECTED(new_size - old_size > heap->limit - heap->real_size)) {
|
||||
if (zend_mm_gc(heap) && new_size - old_size <= heap->limit - heap->real_size) {
|
||||
/* pass */
|
||||
} else if (heap->overflow == 0) {
|
||||
#if ZEND_DEBUG
|
||||
zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)", heap->limit, __zend_filename, __zend_lineno, size);
|
||||
#else
|
||||
zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted (tried to allocate %zu bytes)", heap->limit, size);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
if (UNEXPECTED(zend_mm_check_limit(heap, new_size - old_size, /* gc */ true, NULL ZEND_FILE_LINE_RELAY_CC) == FAILURE)) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* try to map tail right after this block */
|
||||
if (zend_mm_chunk_extend(heap, ptr, old_size, new_size)) {
|
||||
#if ZEND_MM_STAT || ZEND_MM_LIMIT
|
||||
@@ -1791,6 +1928,9 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p
|
||||
if (old_bin_num > 0 && size <= bin_data_size[old_bin_num - 1]) {
|
||||
/* truncation */
|
||||
ret = zend_mm_alloc_small(heap, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
if (UNEXPECTED(ret == NULL)) {
|
||||
goto failed;
|
||||
}
|
||||
copy_size = use_copy_size ? MIN(size, copy_size) : size;
|
||||
memcpy(ret, ptr, copy_size);
|
||||
zend_mm_free_small(heap, ptr, old_bin_num);
|
||||
@@ -1806,6 +1946,9 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p
|
||||
size_t orig_peak = heap->peak;
|
||||
#endif
|
||||
ret = zend_mm_alloc_small(heap, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
if (UNEXPECTED(ret == NULL)) {
|
||||
goto failed;
|
||||
}
|
||||
copy_size = use_copy_size ? MIN(old_size, copy_size) : old_size;
|
||||
memcpy(ret, ptr, copy_size);
|
||||
zend_mm_free_small(heap, ptr, old_bin_num);
|
||||
@@ -1827,6 +1970,10 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p
|
||||
dbg->orig_lineno = __zend_orig_lineno;
|
||||
#endif
|
||||
return ret;
|
||||
|
||||
failed:
|
||||
/* original block is left untouched */
|
||||
return NULL;
|
||||
} while (0);
|
||||
|
||||
} else {
|
||||
@@ -1929,6 +2076,8 @@ static void zend_mm_add_huge_block(zend_mm_heap *heap, void *ptr, size_t size, s
|
||||
static void zend_mm_add_huge_block(zend_mm_heap *heap, void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
#endif
|
||||
{
|
||||
bool was_fallible = heap->fallible;
|
||||
heap->fallible = false;
|
||||
zend_mm_huge_list *list = (zend_mm_huge_list*)zend_mm_alloc_heap(heap, sizeof(zend_mm_huge_list) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
list->ptr = ptr;
|
||||
list->size = size;
|
||||
@@ -1945,6 +2094,7 @@ static void zend_mm_add_huge_block(zend_mm_heap *heap, void *ptr, size_t size ZE
|
||||
list->dbg.orig_lineno = __zend_orig_lineno;
|
||||
#endif
|
||||
heap->huge_list = list;
|
||||
heap->fallible = was_fallible;
|
||||
}
|
||||
|
||||
static size_t zend_mm_del_huge_block(zend_mm_heap *heap, void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
@@ -2029,23 +2179,14 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D
|
||||
void *ptr;
|
||||
|
||||
if (UNEXPECTED(new_size < size)) {
|
||||
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment);
|
||||
zend_mm_delayed_error_or_panic(heap->fallible, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if ZEND_MM_LIMIT
|
||||
if (UNEXPECTED(new_size > heap->limit - heap->real_size)) {
|
||||
if (zend_mm_gc(heap) && new_size <= heap->limit - heap->real_size) {
|
||||
/* pass */
|
||||
} else if (heap->overflow == 0) {
|
||||
#if ZEND_DEBUG
|
||||
zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)", heap->limit, __zend_filename, __zend_lineno, size);
|
||||
#else
|
||||
zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted (tried to allocate %zu bytes)", heap->limit, size);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
if (UNEXPECTED(zend_mm_check_limit(heap, new_size, /* gc */ true, NULL ZEND_FILE_LINE_RELAY_CC) == FAILURE)) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
ptr = zend_mm_chunk_alloc(heap, new_size, ZEND_MM_CHUNK_SIZE);
|
||||
if (UNEXPECTED(ptr == NULL)) {
|
||||
/* insufficient memory */
|
||||
@@ -2053,13 +2194,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D
|
||||
(ptr = zend_mm_chunk_alloc(heap, new_size, ZEND_MM_CHUNK_SIZE)) != NULL) {
|
||||
/* pass */
|
||||
} else {
|
||||
#if !ZEND_MM_LIMIT
|
||||
zend_mm_safe_error(heap, "Out of memory");
|
||||
#elif ZEND_DEBUG
|
||||
zend_mm_safe_error(heap, "Out of memory (allocated %zu bytes) at %s:%d (tried to allocate %zu bytes)", heap->real_size, __zend_filename, __zend_lineno, size);
|
||||
#else
|
||||
zend_mm_safe_error(heap, "Out of memory (allocated %zu bytes) (tried to allocate %zu bytes)", heap->real_size, size);
|
||||
#endif
|
||||
zend_out_of_memory();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -2186,9 +2321,12 @@ static zend_mm_heap *zend_mm_init(void)
|
||||
#endif
|
||||
zend_mm_init_key(heap);
|
||||
#if ZEND_MM_LIMIT
|
||||
heap->limit = (size_t)Z_L(-1) >> 1;
|
||||
heap->limit = ZEND_MM_LIMIT_MAX;
|
||||
heap->hard_limit = ZEND_MM_LIMIT_MAX;
|
||||
heap->hard_limit_percent = -1;
|
||||
heap->overflow = 0;
|
||||
#endif
|
||||
heap->fallible = false;
|
||||
#if ZEND_MM_CUSTOM
|
||||
heap->use_custom_heap = ZEND_MM_CUSTOM_HEAP_NONE;
|
||||
#endif
|
||||
@@ -2556,6 +2694,7 @@ ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
|
||||
if (silent) {
|
||||
tracked_free_all(heap);
|
||||
}
|
||||
heap->max_allocs = 0;
|
||||
zend_hash_clean(heap->tracked_allocs);
|
||||
if (full) {
|
||||
zend_hash_destroy(heap->tracked_allocs);
|
||||
@@ -2939,33 +3078,54 @@ ZEND_API size_t ZEND_FASTCALL _zend_mem_block_size(void *ptr ZEND_FILE_LINE_DC Z
|
||||
return _zend_mm_block_size(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
}
|
||||
|
||||
#define ZEND_MM_SAFE_ADDRESS_GUARDED(dest, nmemb, size, offset) do { \
|
||||
size_t __nmemb = (nmemb); \
|
||||
size_t __size = (size); \
|
||||
size_t __offset = (offset); \
|
||||
bool overflow; \
|
||||
(dest) = zend_safe_address(__nmemb, __size, __offset, &overflow); \
|
||||
if (UNEXPECTED(overflow)) { \
|
||||
zend_mm_delayed_error_or_panic(AG(mm_heap)->fallible, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", __nmemb, __size, __offset); \
|
||||
return NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
ZEND_API void* ZEND_FASTCALL _safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
return _emalloc(zend_safe_address_guarded(nmemb, size, offset) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
size_t actual_size;
|
||||
ZEND_MM_SAFE_ADDRESS_GUARDED(actual_size, nmemb, size, offset);
|
||||
return _emalloc(actual_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
}
|
||||
|
||||
ZEND_API void* ZEND_FASTCALL _safe_malloc(size_t nmemb, size_t size, size_t offset)
|
||||
{
|
||||
return pemalloc(zend_safe_address_guarded(nmemb, size, offset), 1);
|
||||
size_t actual_size;
|
||||
ZEND_MM_SAFE_ADDRESS_GUARDED(actual_size, nmemb, size, offset);
|
||||
return pemalloc(actual_size, 1);
|
||||
}
|
||||
|
||||
ZEND_API void* ZEND_FASTCALL _safe_erealloc(void *ptr, size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
return _erealloc(ptr, zend_safe_address_guarded(nmemb, size, offset) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
size_t actual_size;
|
||||
ZEND_MM_SAFE_ADDRESS_GUARDED(actual_size, nmemb, size, offset);
|
||||
return _erealloc(ptr, actual_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
}
|
||||
|
||||
ZEND_API void* ZEND_FASTCALL _safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset)
|
||||
{
|
||||
return perealloc(ptr, zend_safe_address_guarded(nmemb, size, offset), 1);
|
||||
size_t actual_size;
|
||||
ZEND_MM_SAFE_ADDRESS_GUARDED(actual_size, nmemb, size, offset);
|
||||
return perealloc(ptr, actual_size, 1);
|
||||
}
|
||||
|
||||
ZEND_API void* ZEND_FASTCALL _ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
void *p;
|
||||
size_t actual_size;
|
||||
ZEND_MM_SAFE_ADDRESS_GUARDED(actual_size, nmemb, size, 0);
|
||||
|
||||
size = zend_safe_address_guarded(nmemb, size, 0);
|
||||
p = _emalloc(size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
memset(p, 0, size);
|
||||
p = _emalloc(actual_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
memset(p, 0, actual_size);
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -2976,7 +3136,8 @@ ZEND_API char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_
|
||||
|
||||
length = strlen(s);
|
||||
if (UNEXPECTED(length + 1 == 0)) {
|
||||
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length);
|
||||
zend_mm_delayed_error_or_panic(AG(mm_heap)->fallible, "Possible integer overflow in memory allocation (1 * %zu + 1)", length);
|
||||
return NULL;
|
||||
}
|
||||
p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
memcpy(p, s, length+1);
|
||||
@@ -2988,7 +3149,8 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI
|
||||
char *p;
|
||||
|
||||
if (UNEXPECTED(length + 1 == 0)) {
|
||||
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length);
|
||||
zend_mm_delayed_error_or_panic(AG(mm_heap)->fallible, "Possible integer overflow in memory allocation (1 * %zu + 1)", length);
|
||||
return NULL;
|
||||
}
|
||||
p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
memcpy(p, s, length);
|
||||
@@ -2996,14 +3158,13 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI
|
||||
return p;
|
||||
}
|
||||
|
||||
static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void);
|
||||
|
||||
ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (UNEXPECTED(length + 1 == 0)) {
|
||||
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length);
|
||||
zend_mm_delayed_error_or_panic(AG(mm_heap)->fallible, "Possible integer overflow in memory allocation (1 * %zu + 1)", length);
|
||||
return NULL;
|
||||
}
|
||||
p = (char *) malloc(length + 1);
|
||||
if (UNEXPECTED(p == NULL)) {
|
||||
@@ -3016,11 +3177,119 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length)
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Fallible allocation */
|
||||
|
||||
#define ZEND_MM_FALLIBLE_FORWARD(expr) do { \
|
||||
bool __was_fallible = AG(mm_heap)->fallible; \
|
||||
AG(mm_heap)->fallible = true; \
|
||||
void *__result = (expr); \
|
||||
AG(mm_heap)->fallible = __was_fallible; \
|
||||
return __result; \
|
||||
} while (0)
|
||||
|
||||
ZEND_API void* ZEND_FASTCALL _femalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
ZEND_MM_FALLIBLE_FORWARD(_emalloc(size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC));
|
||||
}
|
||||
|
||||
ZEND_API void* ZEND_FASTCALL _fecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
void *p = _safe_femalloc(nmemb, size, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(p, 0, nmemb * size);
|
||||
return p;
|
||||
}
|
||||
|
||||
ZEND_API void* ZEND_FASTCALL _ferealloc(void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
ZEND_MM_FALLIBLE_FORWARD(_erealloc(ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC));
|
||||
}
|
||||
|
||||
ZEND_API void* ZEND_FASTCALL _ferealloc2(void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
ZEND_MM_FALLIBLE_FORWARD(_erealloc2(ptr, size, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC));
|
||||
}
|
||||
|
||||
ZEND_API void* ZEND_FASTCALL _safe_femalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
ZEND_MM_FALLIBLE_FORWARD(_safe_emalloc(nmemb, size, offset ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC));
|
||||
}
|
||||
|
||||
ZEND_API void* ZEND_FASTCALL _safe_ferealloc(void *ptr, size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
ZEND_MM_FALLIBLE_FORWARD(_safe_erealloc(ptr, nmemb, size, offset ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC));
|
||||
}
|
||||
|
||||
#if ZEND_MM_LIMIT
|
||||
static size_t scale_by_percent(size_t value, zend_long percent)
|
||||
{
|
||||
if (percent <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t p = (size_t)percent;
|
||||
size_t q = value / 100;
|
||||
size_t r = value % 100;
|
||||
|
||||
if (q > SIZE_MAX / p) {
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
size_t hi = q * p;
|
||||
size_t lo = r * (p / 100) + r * (p % 100) / 100;
|
||||
|
||||
if (hi > SIZE_MAX - lo) {
|
||||
return SIZE_MAX;
|
||||
}
|
||||
return hi + lo;
|
||||
}
|
||||
|
||||
static void zend_mm_update_hard_limit(zend_mm_heap *heap)
|
||||
{
|
||||
ZEND_ASSERT(heap->real_size <= heap->limit);
|
||||
|
||||
zend_long percent = heap->hard_limit_percent;
|
||||
|
||||
if (percent == -1) {
|
||||
/* For memory limit >= 1G, use a fixed 1G buffer */
|
||||
if (heap->limit > 1*1024*1024*1024) {
|
||||
size_t offset = 1*1024*1024*1024;
|
||||
if (ZEND_MM_LIMIT_MAX - heap->limit < offset) {
|
||||
heap->hard_limit = ZEND_MM_LIMIT_MAX;
|
||||
} else {
|
||||
heap->hard_limit = heap->limit + offset;
|
||||
}
|
||||
ZEND_ASSERT(heap->hard_limit >= heap->real_size);
|
||||
return;
|
||||
}
|
||||
percent = 200;
|
||||
}
|
||||
|
||||
ZEND_ASSERT(percent >= 100);
|
||||
|
||||
size_t hard_limit = scale_by_percent(heap->limit, percent);
|
||||
if (hard_limit > ZEND_MM_LIMIT_MAX) {
|
||||
hard_limit = ZEND_MM_LIMIT_MAX;
|
||||
}
|
||||
|
||||
heap->hard_limit = hard_limit;
|
||||
ZEND_ASSERT(heap->hard_limit >= heap->real_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
ZEND_API zend_result zend_set_memory_limit(size_t memory_limit)
|
||||
{
|
||||
#if ZEND_MM_LIMIT
|
||||
zend_mm_heap *heap = AG(mm_heap);
|
||||
|
||||
if (memory_limit > ZEND_MM_LIMIT_MAX) {
|
||||
memory_limit = ZEND_MM_LIMIT_MAX;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(memory_limit < heap->real_size)) {
|
||||
if (memory_limit >= heap->real_size - heap->cached_chunks_count * ZEND_MM_CHUNK_SIZE) {
|
||||
/* free some cached chunks to fit into new memory limit */
|
||||
@@ -3031,11 +3300,34 @@ ZEND_API zend_result zend_set_memory_limit(size_t memory_limit)
|
||||
heap->cached_chunks_count--;
|
||||
heap->real_size -= ZEND_MM_CHUNK_SIZE;
|
||||
} while (memory_limit < heap->real_size);
|
||||
heap->limit = memory_limit;
|
||||
zend_mm_update_hard_limit(heap);
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
AG(mm_heap)->limit = memory_limit;
|
||||
heap->limit = memory_limit;
|
||||
zend_mm_update_hard_limit(heap);
|
||||
#endif
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_API zend_result zend_set_memory_hard_limit_percent(zend_long percent)
|
||||
{
|
||||
#if ZEND_MM_LIMIT
|
||||
zend_mm_heap *heap = AG(mm_heap);
|
||||
|
||||
if (percent < 100 && percent != -1) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (heap->real_size > heap->limit) {
|
||||
/* Do not update memory limits while the soft limit is exceeded, as this
|
||||
* could break invariant hard_limit >= real_size. */
|
||||
return FAILURE;
|
||||
}
|
||||
heap->hard_limit_percent = percent;
|
||||
zend_mm_update_hard_limit(heap);
|
||||
#endif
|
||||
return SUCCESS;
|
||||
}
|
||||
@@ -3082,6 +3374,19 @@ ZEND_API void zend_memory_reset_peak_usage(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
ZEND_API void zend_mm_set_max_allocs(uint64_t max_allocs)
|
||||
{
|
||||
#if ZEND_MM_CUSTOM
|
||||
AG(mm_heap)->max_allocs = max_allocs;
|
||||
zend_mm_max_allocs_reached = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
ZEND_API bool zend_mm_max_allocs_hit(void)
|
||||
{
|
||||
return zend_mm_max_allocs_reached;
|
||||
}
|
||||
|
||||
ZEND_API void shutdown_memory_manager(bool silent, bool full_shutdown)
|
||||
{
|
||||
zend_mm_shutdown(AG(mm_heap), full_shutdown, silent);
|
||||
@@ -3114,26 +3419,50 @@ static zend_always_inline zval *tracked_get_size_zv(zend_mm_heap *heap, void *pt
|
||||
return size_zv;
|
||||
}
|
||||
|
||||
static zend_always_inline void tracked_check_limit(zend_mm_heap *heap, size_t add_size) {
|
||||
#if ZEND_MM_STAT
|
||||
if (add_size > heap->limit - heap->size && !heap->overflow) {
|
||||
static zend_always_inline zend_result tracked_check_limit(zend_mm_heap *heap, size_t add_size ZEND_FILE_LINE_DC) {
|
||||
return zend_mm_check_limit(heap, add_size, /* gc */ false, NULL ZEND_FILE_LINE_RELAY_CC);
|
||||
}
|
||||
|
||||
/* ZEND_MM_MAX_ALLOCS fails the n-th allocation of the request in the same way
|
||||
* as the memory limit would, so that the OOM handling can be exercised at an
|
||||
* arbitrary allocation rather than only at the ones large enough to reach the
|
||||
* limit. */
|
||||
static zend_never_inline ZEND_COLD zend_result tracked_max_allocs_error(zend_mm_heap *heap, size_t add_size ZEND_FILE_LINE_DC) {
|
||||
zend_mm_max_allocs_reached = true;
|
||||
|
||||
if (!ZEND_HAS_OOM()) {
|
||||
zend_mm_delayed_error(
|
||||
#if ZEND_DEBUG
|
||||
zend_mm_safe_error(heap,
|
||||
"Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)",
|
||||
heap->limit, "file", 0, add_size);
|
||||
"Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)",
|
||||
#else
|
||||
zend_mm_safe_error(heap,
|
||||
"Allowed memory size of %zu bytes exhausted (tried to allocate %zu bytes)",
|
||||
heap->limit, add_size);
|
||||
"Allowed memory size of %zu bytes exhausted (tried to allocate %zu bytes)",
|
||||
#endif
|
||||
heap->limit
|
||||
ZEND_FILE_LINE_RELAY_CC,
|
||||
add_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
return heap->fallible ? FAILURE : SUCCESS;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_result tracked_check_max_allocs(zend_mm_heap *heap, size_t add_size ZEND_FILE_LINE_DC) {
|
||||
if (UNEXPECTED(heap->max_allocs && !--heap->max_allocs)) {
|
||||
return tracked_max_allocs_error(heap, add_size ZEND_FILE_LINE_RELAY_CC);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static void *tracked_malloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
zend_mm_heap *heap = AG(mm_heap);
|
||||
tracked_check_limit(heap, size);
|
||||
if (UNEXPECTED(tracked_check_limit(heap, size ZEND_FILE_LINE_CC) == FAILURE)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(tracked_check_max_allocs(heap, size ZEND_FILE_LINE_CC) == FAILURE)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *ptr = malloc(size);
|
||||
if (!ptr) {
|
||||
@@ -3173,7 +3502,13 @@ static void *tracked_realloc(void *ptr, size_t new_size ZEND_FILE_LINE_DC ZEND_F
|
||||
}
|
||||
|
||||
if (new_size > old_size) {
|
||||
tracked_check_limit(heap, new_size - old_size);
|
||||
if (UNEXPECTED(tracked_check_limit(heap, new_size - old_size ZEND_FILE_LINE_CC) == FAILURE)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(tracked_check_max_allocs(heap, new_size - old_size ZEND_FILE_LINE_CC) == FAILURE)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete information about old allocation only after checking the memory limit. */
|
||||
@@ -3405,8 +3740,11 @@ static void alloc_globals_ctor(zend_alloc_globals *alloc_globals)
|
||||
zend_mm_heap *mm_heap = alloc_globals->mm_heap = malloc(sizeof(zend_mm_heap));
|
||||
memset(mm_heap, 0, sizeof(zend_mm_heap));
|
||||
mm_heap->use_custom_heap = ZEND_MM_CUSTOM_HEAP_STD;
|
||||
mm_heap->limit = (size_t)Z_L(-1) >> 1;
|
||||
mm_heap->limit = ZEND_MM_LIMIT_MAX;
|
||||
mm_heap->hard_limit = ZEND_MM_LIMIT_MAX;
|
||||
mm_heap->hard_limit_percent = -1;
|
||||
mm_heap->overflow = 0;
|
||||
mm_heap->fallible = false;
|
||||
|
||||
if (!tracked) {
|
||||
/* Use system allocator. */
|
||||
@@ -3477,6 +3815,16 @@ ZEND_API zend_mm_heap *zend_mm_get_heap(void)
|
||||
return AG(mm_heap);
|
||||
}
|
||||
|
||||
ZEND_API bool zend_mm_is_fallible(void)
|
||||
{
|
||||
return AG(mm_heap)->fallible;
|
||||
}
|
||||
|
||||
ZEND_API void zend_mm_set_fallible(bool fallible)
|
||||
{
|
||||
AG(mm_heap)->fallible = fallible;
|
||||
}
|
||||
|
||||
ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap)
|
||||
{
|
||||
#if ZEND_MM_CUSTOM
|
||||
@@ -3628,8 +3976,9 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void
|
||||
#endif
|
||||
zend_mm_init_key(heap);
|
||||
#if ZEND_MM_LIMIT
|
||||
heap->limit = (size_t)Z_L(-1) >> 1;
|
||||
heap->limit = ZEND_MM_LIMIT_MAX;
|
||||
heap->overflow = 0;
|
||||
heap->fallible = false;
|
||||
#endif
|
||||
#if ZEND_MM_CUSTOM
|
||||
heap->use_custom_heap = 0;
|
||||
@@ -3660,6 +4009,60 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void
|
||||
#endif
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_handle_delayed_oom(void)
|
||||
{
|
||||
zend_oom_info *info = &EG(delayed_oom);
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
|
||||
if (info->state != ZEND_OOM_STATE_PENDING) {
|
||||
return;
|
||||
}
|
||||
info->state = ZEND_OOM_STATE_HANDLING;
|
||||
|
||||
AG(mm_heap)->overflow = 1;
|
||||
|
||||
/* message was allocated persistently, use emalloc() now as error_get_last()
|
||||
* may expose it to userland. */
|
||||
zend_string *message = zend_string_init(ZSTR_VAL(info->message), ZSTR_LEN(info->message), 0);
|
||||
zend_string_release(info->message);
|
||||
info->message = message;
|
||||
|
||||
if (execute_data) {
|
||||
/* An exception may already be in flight, and zend_throw_unwind_exit()
|
||||
* does not allow that */
|
||||
EG(exception) = NULL;
|
||||
|
||||
/* Object allocation should succeed unless it trips the hard limit */
|
||||
zend_throw_unwind_exit();
|
||||
}
|
||||
|
||||
zend_try {
|
||||
zend_error_zstr_at(E_ERROR, info->filename, info->lineno, info->message);
|
||||
} zend_catch {
|
||||
} zend_end_try();
|
||||
|
||||
AG(mm_heap)->overflow = 0;
|
||||
|
||||
/* Bailout discards EG(current_execute_data). Would be better to avoid the bailout here. */
|
||||
EG(current_execute_data) = execute_data;
|
||||
|
||||
/* This function may be called from the VM interrupt handler: opline is not
|
||||
* executed yet. Set opline_before_exception to NULL so
|
||||
* ZEND_HANDLE_EXCEPTION does not use it. */
|
||||
EG(opline_before_exception) = NULL;
|
||||
|
||||
zend_mm_oom_info_dtor(info);
|
||||
info->state = ZEND_OOM_STATE_HANDLED;
|
||||
|
||||
/* No userland frame to unwind: there is nothing to restore afterwards
|
||||
* and no exception to throw, so catching the bailout here would just
|
||||
* let the request carry on past a fatal error. Let it propagate and
|
||||
* abort the request, the way an immediate OOM does. */
|
||||
if (!execute_data) {
|
||||
zend_bailout();
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API void * __zend_malloc(size_t len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
void *tmp = malloc(len);
|
||||
@@ -3672,10 +4075,11 @@ ZEND_API void * __zend_malloc(size_t len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_D
|
||||
ZEND_API void * __zend_calloc(size_t nmemb, size_t len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
|
||||
{
|
||||
void *tmp;
|
||||
size_t actual_size;
|
||||
ZEND_MM_SAFE_ADDRESS_GUARDED(actual_size, nmemb, len, 0);
|
||||
|
||||
len = zend_safe_address_guarded(nmemb, len, 0);
|
||||
tmp = __zend_malloc(len ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
memset(tmp, 0, len);
|
||||
tmp = __zend_malloc(actual_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
|
||||
memset(tmp, 0, actual_size);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -3702,4 +4106,3 @@ ZEND_API char * __zend_strdup(const char *s)
|
||||
}
|
||||
zend_out_of_memory();
|
||||
}
|
||||
|
||||
@@ -36,6 +36,20 @@
|
||||
#define ZEND_MM_ALIGNED_SIZE_EX(size, alignment) \
|
||||
(((size) + ((alignment) - 1)) & ~((alignment) - 1))
|
||||
|
||||
typedef enum _zend_oom_state {
|
||||
ZEND_OOM_STATE_NONE = 0,
|
||||
ZEND_OOM_STATE_PENDING,
|
||||
ZEND_OOM_STATE_HANDLING,
|
||||
ZEND_OOM_STATE_HANDLED
|
||||
} zend_oom_state;
|
||||
|
||||
typedef struct _zend_oom_info {
|
||||
zend_oom_state state;
|
||||
uint32_t lineno;
|
||||
zend_string *message;
|
||||
zend_string *filename;
|
||||
} zend_oom_info;
|
||||
|
||||
typedef struct _zend_leak_info {
|
||||
void *addr;
|
||||
size_t size;
|
||||
@@ -45,6 +59,8 @@ typedef struct _zend_leak_info {
|
||||
uint32_t orig_lineno;
|
||||
} zend_leak_info;
|
||||
|
||||
#define ZEND_HAS_OOM() (UNEXPECTED(EG(delayed_oom).state != ZEND_OOM_STATE_NONE))
|
||||
|
||||
#if ZEND_DEBUG
|
||||
typedef struct _zend_mm_debug_info {
|
||||
size_t size;
|
||||
@@ -214,7 +230,40 @@ ZEND_API ZEND_ATTRIBUTE_MALLOC char * __zend_strdup(const char *s);
|
||||
#define perealloc2_recoverable_rel(ptr, size, copy_size, persistent) ((persistent)?realloc((ptr), (size)):erealloc2_recoverable_rel((ptr), (size), (copy_size)))
|
||||
#define pestrdup_rel(s, persistent) ((persistent)?strdup(s):estrdup_rel(s))
|
||||
|
||||
/* Fallible allocation.
|
||||
* These functions return NULL if allocation would exceed memory limit. */
|
||||
|
||||
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _femalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE(1);
|
||||
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _fecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE2(1,2);
|
||||
ZEND_API void* ZEND_FASTCALL _ferealloc(void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE(2);
|
||||
ZEND_API void* ZEND_FASTCALL _ferealloc2(void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE(2);
|
||||
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _safe_femalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
|
||||
ZEND_API void* ZEND_FASTCALL _safe_ferealloc(void *ptr, size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
|
||||
|
||||
#define femalloc(size, fallible) \
|
||||
((fallible)?_femalloc((size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):_emalloc((size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC))
|
||||
#define fecalloc(nmemb, size, fallible) \
|
||||
((fallible)?_fecalloc((nmemb), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):_ecalloc((nmemb), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC))
|
||||
#define ferealloc(ptr, size, fallible) \
|
||||
((fallible)?_ferealloc((ptr), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):_erealloc((ptr), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC))
|
||||
#define ferealloc2(ptr, size, copy_size, fallible) \
|
||||
((fallible)?_ferealloc2((ptr), (size), (copy_size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):_erealloc2((ptr), (size), (copy_size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC))
|
||||
#define safe_femalloc(nmemb, size, offset, fallible) \
|
||||
((fallible)?_safe_femalloc((nmemb), (size), (offset) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):_safe_emalloc((nmemb), (size), (offset) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC))
|
||||
#define safe_ferealloc(ptr, nmemb, size, offset, fallible) \
|
||||
((fallible)?_safe_ferealloc((ptr), (nmemb), (size), (offset) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):_safe_erealloc((ptr), (nmemb), (size), (offset) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC))
|
||||
|
||||
#define fpemalloc(size, persistent, fallible) \
|
||||
((persistent)?__zend_malloc(size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):femalloc(size, fallible))
|
||||
#define fperealloc(ptr, size, persistent, fallible) ((persistent)?__zend_realloc((ptr), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):ferealloc((ptr), (size), (fallible)))
|
||||
#define fperealloc2(ptr, size, copy_size, persistent, fallible) ((persistent)?__zend_realloc((ptr), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):ferealloc2((ptr), (size), (copy_size), (fallible)))
|
||||
#define safe_fpemalloc(nmemb, size, offset, persistent, fallible) \
|
||||
((persistent)?_safe_malloc(nmemb, size, offset):safe_femalloc(nmemb, size, offset, fallible))
|
||||
#define safe_fperealloc(ptr, nmemb, size, offset, persistent, fallible) \
|
||||
((persistent)?_safe_realloc(ptr, nmemb, size, offset):safe_ferealloc(ptr, nmemb, size, offset, fallible))
|
||||
|
||||
ZEND_API zend_result zend_set_memory_limit(size_t memory_limit);
|
||||
ZEND_API zend_result zend_set_memory_hard_limit_percent(zend_long percent);
|
||||
ZEND_API bool zend_alloc_in_memory_limit_error_reporting(void);
|
||||
|
||||
ZEND_API void start_memory_manager(void);
|
||||
@@ -268,6 +317,9 @@ ZEND_API zend_mm_heap *zend_mm_get_heap(void);
|
||||
|
||||
ZEND_API size_t zend_mm_gc(zend_mm_heap *heap);
|
||||
|
||||
ZEND_API bool zend_mm_is_fallible(void);
|
||||
ZEND_API void zend_mm_set_fallible(bool fallible);
|
||||
|
||||
#define ZEND_MM_CUSTOM_HEAP_NONE 0
|
||||
#define ZEND_MM_CUSTOM_HEAP_STD 1
|
||||
#define ZEND_MM_CUSTOM_HEAP_DEBUG 2
|
||||
@@ -318,6 +370,17 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void
|
||||
|
||||
ZEND_API void zend_mm_refresh_key_child(zend_mm_heap *heap);
|
||||
|
||||
ZEND_API ZEND_COLD void zend_mm_delayed_error_or_panic(bool delay, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
|
||||
ZEND_API void ZEND_FASTCALL zend_handle_delayed_oom(void);
|
||||
ZEND_COLD void zend_mm_oom_info_dtor(zend_oom_info *info);
|
||||
|
||||
/* Exit status of a process that stopped because of ZEND_MM_MAX_ALLOCS, so that
|
||||
* it can be told apart from an ordinary fatal error. */
|
||||
#define ZEND_MM_MAX_ALLOCS_EXIT_STATUS 121
|
||||
|
||||
ZEND_API void zend_mm_set_max_allocs(uint64_t max_allocs);
|
||||
ZEND_API bool zend_mm_max_allocs_hit(void);
|
||||
|
||||
/*
|
||||
|
||||
// The following example shows how to use zend_mm_heap API with custom storage
|
||||
|
||||
@@ -155,6 +155,12 @@ ZEND_METHOD(SensitiveParameter, __construct)
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
}
|
||||
|
||||
void zend_sensitive_parameter_value_init(zend_object *obj, zval *value)
|
||||
{
|
||||
ZEND_ASSERT(obj->ce == zend_ce_sensitive_parameter_value);
|
||||
zend_update_property_ex(zend_ce_sensitive_parameter_value, obj, ZSTR_KNOWN(ZEND_STR_VALUE), value);
|
||||
}
|
||||
|
||||
ZEND_METHOD(SensitiveParameterValue, __construct)
|
||||
{
|
||||
zval *value;
|
||||
@@ -163,7 +169,7 @@ ZEND_METHOD(SensitiveParameterValue, __construct)
|
||||
Z_PARAM_ZVAL(value)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
zend_update_property_ex(zend_ce_sensitive_parameter_value, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_VALUE), value);
|
||||
zend_sensitive_parameter_value_init(Z_OBJ_P(ZEND_THIS), value);
|
||||
}
|
||||
|
||||
ZEND_METHOD(SensitiveParameterValue, getValue)
|
||||
|
||||
@@ -139,4 +139,6 @@ static zend_always_inline zend_attribute *zend_add_global_constant_attribute(zen
|
||||
void zend_register_attribute_ce(void);
|
||||
void zend_attributes_shutdown(void);
|
||||
|
||||
void zend_sensitive_parameter_value_init(zend_object *obj, zval *value);
|
||||
|
||||
#endif
|
||||
@@ -1723,7 +1723,7 @@ static bool backtrace_is_arg_sensitive(const zend_execute_data *call, uint32_t o
|
||||
return attribute != NULL;
|
||||
}
|
||||
|
||||
static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /* {{{ */
|
||||
static bool debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /* {{{ */
|
||||
{
|
||||
uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
|
||||
|
||||
@@ -1731,8 +1731,9 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /
|
||||
uint32_t i = 0;
|
||||
zval *p = ZEND_CALL_ARG(call, 1);
|
||||
|
||||
array_init_size(arg_array, num_args);
|
||||
zend_hash_real_init_packed(Z_ARRVAL_P(arg_array));
|
||||
if (!array_finit_size_packed(arg_array, num_args)) {
|
||||
return false;
|
||||
}
|
||||
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(arg_array)) {
|
||||
if (call->func->type == ZEND_USER_FUNCTION) {
|
||||
uint32_t first_extra_arg = MIN(num_args, call->func->op_array.num_args);
|
||||
@@ -1757,8 +1758,14 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /
|
||||
|
||||
if (is_sensitive) {
|
||||
zval redacted_arg;
|
||||
object_init_with_constructor(&redacted_arg, zend_ce_sensitive_parameter_value, 1, &original_arg, NULL);
|
||||
object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
|
||||
zend_sensitive_parameter_value_init(Z_OBJ(redacted_arg), &original_arg);
|
||||
ZEND_HASH_FILL_SET(&redacted_arg);
|
||||
if (ZEND_HAS_OOM()) {
|
||||
zval_ptr_dtor(&redacted_arg);
|
||||
ZEND_HASH_FILL_FINISH();
|
||||
goto oom;
|
||||
}
|
||||
} else {
|
||||
Z_TRY_ADDREF_P(&original_arg);
|
||||
ZEND_HASH_FILL_SET(&original_arg);
|
||||
@@ -1782,8 +1789,14 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /
|
||||
|
||||
if (is_sensitive) {
|
||||
zval redacted_arg;
|
||||
object_init_with_constructor(&redacted_arg, zend_ce_sensitive_parameter_value, 1, &original_arg, NULL);
|
||||
object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
|
||||
zend_sensitive_parameter_value_init(Z_OBJ(redacted_arg), &original_arg);
|
||||
ZEND_HASH_FILL_SET(&redacted_arg);
|
||||
if (ZEND_HAS_OOM()) {
|
||||
zval_ptr_dtor(&redacted_arg);
|
||||
ZEND_HASH_FILL_FINISH();
|
||||
goto oom;
|
||||
}
|
||||
} else {
|
||||
Z_TRY_ADDREF_P(&original_arg);
|
||||
ZEND_HASH_FILL_SET(&original_arg);
|
||||
@@ -1815,8 +1828,14 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /
|
||||
|
||||
if (is_sensitive) {
|
||||
zval redacted_arg;
|
||||
object_init_with_constructor(&redacted_arg, zend_ce_sensitive_parameter_value, 1, &original_arg, NULL);
|
||||
object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
|
||||
zend_sensitive_parameter_value_init(Z_OBJ(redacted_arg), &original_arg);
|
||||
ZEND_HASH_FILL_SET(&redacted_arg);
|
||||
if (ZEND_HAS_OOM()) {
|
||||
zval_ptr_dtor(&redacted_arg);
|
||||
ZEND_HASH_FILL_FINISH();
|
||||
goto oom;
|
||||
}
|
||||
} else {
|
||||
Z_TRY_ADDREF_P(&original_arg);
|
||||
ZEND_HASH_FILL_SET(&original_arg);
|
||||
@@ -1845,16 +1864,28 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /
|
||||
SEPARATE_ARRAY(arg_array);
|
||||
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(call->extra_named_params, name, arg) {
|
||||
ZVAL_DEREF(arg);
|
||||
zval *add_result;
|
||||
if (is_sensitive) {
|
||||
zval redacted_arg;
|
||||
object_init_with_constructor(&redacted_arg, zend_ce_sensitive_parameter_value, 1, arg, NULL);
|
||||
zend_hash_add_new(Z_ARRVAL_P(arg_array), name, &redacted_arg);
|
||||
object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
|
||||
zend_sensitive_parameter_value_init(Z_OBJ(redacted_arg), arg);
|
||||
add_result = zend_hash_fadd_new(Z_ARRVAL_P(arg_array), name, &redacted_arg);
|
||||
} else {
|
||||
Z_TRY_ADDREF_P(arg);
|
||||
zend_hash_add_new(Z_ARRVAL_P(arg_array), name, arg);
|
||||
add_result = zend_hash_fadd_new(Z_ARRVAL_P(arg_array), name, arg);
|
||||
}
|
||||
if (UNEXPECTED(add_result == HASH_NOMEM)) {
|
||||
goto oom;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
oom:
|
||||
zval_ptr_dtor(arg_array);
|
||||
ZVAL_EMPTY_ARRAY(arg_array);
|
||||
return false;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -2119,7 +2150,11 @@ not_frameless_call:
|
||||
if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0 &&
|
||||
func->type != ZEND_EVAL_CODE) {
|
||||
|
||||
debug_backtrace_get_args(call, &tmp);
|
||||
if (UNEXPECTED(!debug_backtrace_get_args(call, &tmp))) {
|
||||
ZEND_ASSERT(ZEND_HAS_OOM());
|
||||
zend_array_destroy(stack_frame);
|
||||
return;
|
||||
}
|
||||
_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_ARGS), &tmp, 1);
|
||||
}
|
||||
} else {
|
||||
@@ -2179,11 +2214,18 @@ not_frameless_call:
|
||||
}
|
||||
|
||||
ZVAL_ARR(&tmp, stack_frame);
|
||||
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
|
||||
if (UNEXPECTED(zend_hash_next_index_finsert_new(Z_ARRVAL_P(return_value), &tmp) == HASH_NOMEM)) {
|
||||
zend_array_destroy(stack_frame);
|
||||
return;
|
||||
}
|
||||
frameno++;
|
||||
prev_stack_frame = stack_frame;
|
||||
|
||||
skip_frame:
|
||||
if (ZEND_HAS_OOM()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(ZEND_CALL_KIND(call) == ZEND_CALL_TOP_FUNCTION)
|
||||
&& !fake_frame
|
||||
&& prev
|
||||
|
||||
@@ -475,6 +475,7 @@ void init_compiler(void) /* {{{ */
|
||||
CG(delayed_autoloads) = NULL;
|
||||
CG(unlinked_uses) = NULL;
|
||||
CG(current_linking_class) = NULL;
|
||||
CG(interned_strings_fallible) = false;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
@@ -109,7 +109,9 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo
|
||||
return;
|
||||
}
|
||||
|
||||
if (exception == add_previous || zend_is_unwind_exit(add_previous) || zend_is_graceful_exit(add_previous)) {
|
||||
if (exception == add_previous
|
||||
|| zend_is_unwind_exit(exception) || zend_is_graceful_exit(exception)
|
||||
|| zend_is_unwind_exit(add_previous) || zend_is_graceful_exit(add_previous)) {
|
||||
OBJ_RELEASE(add_previous);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4347,6 +4347,8 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_fcall_interrupt(zend_execute_data *ca
|
||||
zend_atomic_bool_store_ex(&EG(vm_interrupt), false);
|
||||
if (zend_atomic_bool_load_ex(&EG(timed_out))) {
|
||||
zend_timeout();
|
||||
} else if (ZEND_HAS_OOM()) {
|
||||
zend_handle_delayed_oom();
|
||||
} else if (zend_interrupt_function) {
|
||||
zend_interrupt_function(call);
|
||||
}
|
||||
@@ -4950,6 +4952,18 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* Same as cleanup_unfinished_calls(), but only free the call frames. */
|
||||
static void free_unfinished_calls(zend_execute_data *execute_data)
|
||||
{
|
||||
zend_execute_data *call = EX(call);
|
||||
|
||||
while (UNEXPECTED(call != NULL)) {
|
||||
EX(call) = call->prev_execute_data;
|
||||
zend_vm_stack_free_call_frame(call);
|
||||
call = EX(call);
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
|
||||
{
|
||||
for (uint32_t i = 0; i < EX(func)->op_array.last_live_range; i++) {
|
||||
|
||||
+37
-14
@@ -438,10 +438,24 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown)
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* may be used by zend_error_zstr_at before init_executor */
|
||||
ZVAL_UNDEF(&EG(user_error_handler));
|
||||
ZVAL_UNDEF(&EG(user_exception_handler));
|
||||
memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting)));
|
||||
memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers)));
|
||||
memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers)));
|
||||
|
||||
zend_hash_discard(EG(zend_constants), EG(persistent_constants_count));
|
||||
}
|
||||
|
||||
zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown);
|
||||
|
||||
/* may be used by zend_error_zstr_at before init_executor */
|
||||
ZVAL_UNDEF(&EG(last_fatal_error_backtrace));
|
||||
EG(record_errors) = false;
|
||||
memset(&EG(errors), 0, sizeof(EG(errors)));
|
||||
EG(error_handling) = EH_NORMAL;
|
||||
EG(exception) = NULL;
|
||||
}
|
||||
|
||||
void shutdown_executor(void) /* {{{ */
|
||||
@@ -480,6 +494,8 @@ void shutdown_executor(void) /* {{{ */
|
||||
*/
|
||||
zend_hash_discard(EG(function_table), EG(persistent_functions_count));
|
||||
zend_hash_discard(EG(class_table), EG(persistent_classes_count));
|
||||
EG(objects_store).object_buckets = NULL;
|
||||
EG(objects_store).top = 1;
|
||||
} else {
|
||||
zend_vm_stack_destroy();
|
||||
zend_vm_stack_destroy_caches();
|
||||
@@ -830,7 +846,11 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
|
||||
if (!EG(active)) {
|
||||
return FAILURE; /* executor is already inactive */
|
||||
}
|
||||
|
||||
if (ZEND_HAS_OOM()) {
|
||||
/* Callers expect SUCCESS || EG(exception), so let's throw right now */
|
||||
zend_handle_delayed_oom();
|
||||
return FAILURE;
|
||||
}
|
||||
if (EG(exception)) {
|
||||
if (fci_cache) {
|
||||
zend_release_fcall_info_cache(fci_cache);
|
||||
@@ -1078,7 +1098,7 @@ cleanup_args:
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -1102,21 +1122,24 @@ cleanup_args:
|
||||
zval_ptr_dtor(fci->retval);
|
||||
ZVAL_UNDEF(fci->retval);
|
||||
}
|
||||
}
|
||||
|
||||
/* This flag is regularly checked while running user functions, but not internal
|
||||
* So see whether interrupt flag was set while the function was running... */
|
||||
if (zend_atomic_bool_exchange_ex(&EG(vm_interrupt), false)) {
|
||||
if (zend_atomic_bool_load_ex(&EG(timed_out))) {
|
||||
zend_timeout();
|
||||
} else if (zend_interrupt_function) {
|
||||
zend_interrupt_function(EG(current_execute_data));
|
||||
}
|
||||
}
|
||||
|
||||
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
|
||||
OBJ_RELEASE(Z_OBJ(call->This));
|
||||
if (UNEXPECTED(zend_atomic_bool_exchange_ex(&EG(vm_interrupt), false))) {
|
||||
if (zend_atomic_bool_load_ex(&EG(timed_out))) {
|
||||
zend_timeout();
|
||||
} else if (ZEND_HAS_OOM()) {
|
||||
zend_handle_delayed_oom();
|
||||
zval_ptr_dtor(fci->retval);
|
||||
ZVAL_UNDEF(fci->retval);
|
||||
} else if (zend_interrupt_function) {
|
||||
zend_interrupt_function(EG(current_execute_data));
|
||||
}
|
||||
}
|
||||
|
||||
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
|
||||
OBJ_RELEASE(Z_OBJ(call->This));
|
||||
}
|
||||
|
||||
EG(fake_scope) = orig_fake_scope;
|
||||
|
||||
if (pinned_this) {
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "zend_globals_macros.h"
|
||||
|
||||
#include "zend_alloc.h"
|
||||
#include "zend_atomic.h"
|
||||
#include "zend_stack.h"
|
||||
#include "zend_ptr_stack.h"
|
||||
@@ -140,6 +141,7 @@ struct _zend_compiler_globals {
|
||||
bool multibyte;
|
||||
bool detect_unicode;
|
||||
bool encoding_declared;
|
||||
bool interned_strings_fallible;
|
||||
|
||||
zend_ast *ast;
|
||||
zend_arena *ast_arena;
|
||||
@@ -335,6 +337,8 @@ struct _zend_executor_globals {
|
||||
uint32_t fiber_vm_stack_page_cache_count;
|
||||
|
||||
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
|
||||
|
||||
zend_oom_info delayed_oom;
|
||||
};
|
||||
|
||||
#ifdef ZTS
|
||||
|
||||
+263
-44
@@ -82,7 +82,10 @@ static void _zend_is_inconsistent(const HashTable *ht, const char *file, int lin
|
||||
|
||||
#define ZEND_HASH_IF_FULL_DO_RESIZE(ht) \
|
||||
if ((ht)->nNumUsed >= (ht)->nTableSize) { \
|
||||
zend_hash_do_resize(ht); \
|
||||
zend_result _resize_status = zend_hash_do_fresize(ht, flag & HASH_FALLIBLE); \
|
||||
if (ZEND_CONST_COND(flag & HASH_FALLIBLE, true) && UNEXPECTED(_resize_status == FAILURE)) { \
|
||||
return HASH_NOMEM; \
|
||||
} \
|
||||
}
|
||||
|
||||
ZEND_API void *zend_hash_str_find_ptr_lc(const HashTable *ht, const char *str, size_t len) {
|
||||
@@ -107,9 +110,9 @@ ZEND_API void *zend_hash_find_ptr_lc(const HashTable *ht, zend_string *key) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht);
|
||||
static zend_result ZEND_FASTCALL zend_hash_do_fresize(HashTable *ht, bool fallible);
|
||||
|
||||
static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize)
|
||||
static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize, bool fallible)
|
||||
{
|
||||
#ifdef ZEND_WIN32
|
||||
unsigned long index;
|
||||
@@ -120,7 +123,8 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize)
|
||||
if (nSize <= HT_MIN_SIZE) {
|
||||
return HT_MIN_SIZE;
|
||||
} else if (UNEXPECTED(nSize > HT_MAX_SIZE)) {
|
||||
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket));
|
||||
zend_mm_delayed_error_or_panic(fallible, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ZEND_WIN32
|
||||
@@ -144,25 +148,34 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize)
|
||||
#endif
|
||||
}
|
||||
|
||||
static zend_always_inline void zend_hash_real_init_packed_ex(HashTable *ht)
|
||||
static zend_always_inline zend_result zend_hash_real_finit_packed_ex(HashTable *ht, bool fallible)
|
||||
{
|
||||
void *data;
|
||||
|
||||
if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) {
|
||||
data = pemalloc(HT_PACKED_SIZE_EX(ht->nTableSize, HT_MIN_MASK), 1);
|
||||
data = fpemalloc(HT_PACKED_SIZE_EX(ht->nTableSize, HT_MIN_MASK), true, fallible);
|
||||
} else if (EXPECTED(ht->nTableSize == HT_MIN_SIZE)) {
|
||||
/* Use specialized API with constant allocation amount for a particularly common case. */
|
||||
data = emalloc(HT_PACKED_SIZE_EX(HT_MIN_SIZE, HT_MIN_MASK));
|
||||
data = femalloc(HT_PACKED_SIZE_EX(HT_MIN_SIZE, HT_MIN_MASK), fallible);
|
||||
} else {
|
||||
data = emalloc(HT_PACKED_SIZE_EX(ht->nTableSize, HT_MIN_MASK));
|
||||
data = femalloc(HT_PACKED_SIZE_EX(ht->nTableSize, HT_MIN_MASK), fallible);
|
||||
}
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!data)) {
|
||||
return FAILURE;
|
||||
}
|
||||
HT_SET_DATA_ADDR(ht, data);
|
||||
/* Don't overwrite iterator count. */
|
||||
ht->u.v.flags = HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
|
||||
HT_HASH_RESET_PACKED(ht);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht)
|
||||
static zend_always_inline void zend_hash_real_init_packed_ex(HashTable *ht)
|
||||
{
|
||||
zend_hash_real_finit_packed_ex(ht, /* fallible */ false);
|
||||
}
|
||||
|
||||
static zend_always_inline zend_result zend_hash_real_finit_mixed_ex(HashTable *ht, bool fallible)
|
||||
{
|
||||
void *data;
|
||||
uint32_t nSize = ht->nTableSize;
|
||||
@@ -170,9 +183,15 @@ static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht)
|
||||
ZEND_ASSERT(HT_SIZE_TO_MASK(nSize) != 0);
|
||||
|
||||
if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) {
|
||||
data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), 1);
|
||||
data = fpemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), true, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!data)) {
|
||||
return FAILURE;
|
||||
}
|
||||
} else if (EXPECTED(nSize == HT_MIN_SIZE)) {
|
||||
data = emalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_SIZE_TO_MASK(HT_MIN_SIZE)));
|
||||
data = femalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_SIZE_TO_MASK(HT_MIN_SIZE)), fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!data)) {
|
||||
return FAILURE;
|
||||
}
|
||||
ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE);
|
||||
HT_SET_DATA_ADDR(ht, data);
|
||||
/* Don't overwrite iterator count. */
|
||||
@@ -219,27 +238,42 @@ static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht)
|
||||
HT_HASH_EX(data, 14) = -1;
|
||||
HT_HASH_EX(data, 15) = -1;
|
||||
#endif
|
||||
return;
|
||||
return SUCCESS;
|
||||
} else {
|
||||
data = emalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)));
|
||||
data = femalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!data)) {
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
ht->nTableMask = HT_SIZE_TO_MASK(nSize);
|
||||
HT_SET_DATA_ADDR(ht, data);
|
||||
HT_FLAGS(ht) = HASH_FLAG_STATIC_KEYS;
|
||||
HT_HASH_RESET(ht);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static zend_always_inline void zend_hash_real_init_ex(HashTable *ht, bool packed)
|
||||
static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht)
|
||||
{
|
||||
zend_hash_real_finit_mixed_ex(ht, /* fallible */ false);
|
||||
}
|
||||
|
||||
static zend_always_inline zend_result zend_hash_real_finit_ex(HashTable *ht, bool packed, bool fallible)
|
||||
{
|
||||
HT_ASSERT_RC1(ht);
|
||||
ZEND_ASSERT(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED);
|
||||
if (packed) {
|
||||
zend_hash_real_init_packed_ex(ht);
|
||||
return zend_hash_real_finit_packed_ex(ht, fallible);
|
||||
} else {
|
||||
zend_hash_real_init_mixed_ex(ht);
|
||||
return zend_hash_real_finit_mixed_ex(ht, fallible);
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline void zend_hash_real_init_ex(HashTable *ht, bool packed)
|
||||
{
|
||||
zend_hash_real_finit_ex(ht, packed, /* fallible */ false);
|
||||
}
|
||||
|
||||
static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
|
||||
{HT_INVALID_IDX, HT_INVALID_IDX};
|
||||
|
||||
@@ -257,7 +291,7 @@ ZEND_API const HashTable zend_empty_array = {
|
||||
.pDestructor = ZVAL_PTR_DTOR
|
||||
};
|
||||
|
||||
static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, bool persistent)
|
||||
static zend_always_inline zend_result _zend_hash_finit_int(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, bool persistent, bool fallible)
|
||||
{
|
||||
GC_SET_REFCOUNT(ht, 1);
|
||||
GC_TYPE_INFO(ht) = GC_ARRAY | (persistent ? ((GC_PERSISTENT|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT) : 0);
|
||||
@@ -269,7 +303,16 @@ static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize
|
||||
ht->nInternalPointer = 0;
|
||||
ht->nNextFreeElement = ZEND_LONG_MIN;
|
||||
ht->pDestructor = pDestructor;
|
||||
ht->nTableSize = zend_hash_check_size(nSize);
|
||||
ht->nTableSize = zend_hash_check_size(nSize, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!ht->nTableSize)) {
|
||||
return FAILURE;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, bool persistent)
|
||||
{
|
||||
_zend_hash_finit_int(ht, nSize, pDestructor, persistent, /* fallible */ false);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, bool persistent)
|
||||
@@ -284,6 +327,26 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void)
|
||||
return ht;
|
||||
}
|
||||
|
||||
ZEND_API HashTable* ZEND_FASTCALL _zend_fnew_array_0(void)
|
||||
{
|
||||
HashTable *ht = femalloc(sizeof(HashTable), /* fallible */ true);
|
||||
if (UNEXPECTED(ht == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
if (UNEXPECTED(_zend_hash_finit_int(ht, HT_MIN_SIZE, ZVAL_PTR_DTOR, /* persistent */ false, /* fallible */ true) == FAILURE)) {
|
||||
efree(ht);
|
||||
return NULL;
|
||||
}
|
||||
return ht;
|
||||
}
|
||||
|
||||
ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void)
|
||||
{
|
||||
HashTable *ht = _zend_new_array_0();
|
||||
ht->nTableSize = 1;
|
||||
return ht;
|
||||
}
|
||||
|
||||
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize)
|
||||
{
|
||||
HashTable *ht = emalloc(sizeof(HashTable));
|
||||
@@ -291,6 +354,20 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize)
|
||||
return ht;
|
||||
}
|
||||
|
||||
ZEND_API HashTable* ZEND_FASTCALL _zend_fnew_array(uint32_t nSize)
|
||||
{
|
||||
HashTable *ht = femalloc(sizeof(HashTable), /* fallible */ true);
|
||||
if (UNEXPECTED(ht == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(_zend_hash_finit_int(ht, nSize, ZVAL_PTR_DTOR, /* persistent */ false, /* fallible */ true) == FAILURE)) {
|
||||
efree(ht);
|
||||
return NULL;
|
||||
}
|
||||
return ht;
|
||||
}
|
||||
|
||||
ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(const zval *val1, const zval *val2)
|
||||
{
|
||||
zval *zv;
|
||||
@@ -306,15 +383,26 @@ ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(const zval *val1, const zval *va
|
||||
return ht;
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht)
|
||||
ZEND_API zend_result ZEND_FASTCALL zend_hash_packed_fgrow(HashTable *ht, bool fallible)
|
||||
{
|
||||
HT_ASSERT_RC1(ht);
|
||||
if (ht->nTableSize >= HT_MAX_SIZE) {
|
||||
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket));
|
||||
zend_mm_delayed_error_or_panic(fallible, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket));
|
||||
return FAILURE;
|
||||
}
|
||||
uint32_t newTableSize = ht->nTableSize * 2;
|
||||
HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_PACKED_SIZE_EX(newTableSize, HT_MIN_MASK), HT_PACKED_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT));
|
||||
void *newData = fperealloc2(HT_GET_DATA_ADDR(ht), HT_PACKED_SIZE_EX(newTableSize, HT_MIN_MASK), HT_PACKED_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!newData)) {
|
||||
return FAILURE;
|
||||
}
|
||||
HT_SET_DATA_ADDR(ht, newData);
|
||||
ht->nTableSize = newTableSize;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht)
|
||||
{
|
||||
zend_hash_packed_fgrow(ht, /* fallible */ false);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, bool packed)
|
||||
@@ -325,6 +413,14 @@ ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, bool packed)
|
||||
zend_hash_real_init_ex(ht, packed);
|
||||
}
|
||||
|
||||
ZEND_API zend_result ZEND_FASTCALL zend_hash_real_finit(HashTable *ht, bool packed, bool fallible)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
HT_ASSERT_RC1(ht);
|
||||
return zend_hash_real_finit_ex(ht, packed, fallible);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_real_init_packed(HashTable *ht)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
@@ -333,6 +429,15 @@ ZEND_API void ZEND_FASTCALL zend_hash_real_init_packed(HashTable *ht)
|
||||
zend_hash_real_init_packed_ex(ht);
|
||||
}
|
||||
|
||||
/* Fallible variant of zend_hash_real_init_packed */
|
||||
ZEND_API zend_result ZEND_FASTCALL zend_hash_real_finit_packed(HashTable *ht, bool fallible)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
HT_ASSERT_RC1(ht);
|
||||
return zend_hash_real_finit_packed_ex(ht, fallible);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_real_init_mixed(HashTable *ht)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
@@ -341,7 +446,16 @@ ZEND_API void ZEND_FASTCALL zend_hash_real_init_mixed(HashTable *ht)
|
||||
zend_hash_real_init_mixed_ex(ht);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht)
|
||||
/* Fallible variant of zend_hash_real_init_mixed */
|
||||
ZEND_API zend_result ZEND_FASTCALL zend_hash_real_finit_mixed(HashTable *ht, bool fallible)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
HT_ASSERT_RC1(ht);
|
||||
return zend_hash_real_finit_mixed_ex(ht, fallible);
|
||||
}
|
||||
|
||||
ZEND_API zend_result ZEND_FASTCALL zend_hash_fconvert_packed_to_hash(HashTable *ht, bool fallible)
|
||||
{
|
||||
void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
|
||||
zval *src = ht->arPacked;
|
||||
@@ -353,7 +467,10 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht)
|
||||
|
||||
HT_ASSERT_RC1(ht);
|
||||
// Alloc before assign to avoid inconsistencies on OOM
|
||||
new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
|
||||
new_data = fpemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!new_data)) {
|
||||
return FAILURE;
|
||||
}
|
||||
HT_FLAGS(ht) &= ~HASH_FLAG_PACKED;
|
||||
ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
|
||||
HT_SET_DATA_ADDR(ht, new_data);
|
||||
@@ -367,6 +484,12 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht)
|
||||
}
|
||||
pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
|
||||
zend_hash_rehash(ht);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht)
|
||||
{
|
||||
zend_hash_fconvert_packed_to_hash(ht, /* fallible */ false);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht)
|
||||
@@ -391,25 +514,39 @@ ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht)
|
||||
pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool packed)
|
||||
static zend_always_inline zend_result ZEND_FASTCALL _zend_hash_fextend(HashTable *ht, uint32_t nSize, bool packed, bool fallible)
|
||||
{
|
||||
HT_ASSERT_RC1(ht);
|
||||
|
||||
if (nSize == 0) return;
|
||||
if (nSize == 0) return SUCCESS;
|
||||
|
||||
ZEND_ASSERT(HT_SIZE_TO_MASK(nSize) != 0);
|
||||
|
||||
if (UNEXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
|
||||
if (nSize > ht->nTableSize) {
|
||||
ht->nTableSize = zend_hash_check_size(nSize);
|
||||
uint32_t newTableSize = zend_hash_check_size(nSize, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!newTableSize)) {
|
||||
return FAILURE;
|
||||
}
|
||||
ht->nTableSize = newTableSize;
|
||||
}
|
||||
zend_result status = zend_hash_real_finit(ht, packed, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(status == FAILURE)) {
|
||||
return FAILURE;
|
||||
}
|
||||
zend_hash_real_init(ht, packed);
|
||||
} else {
|
||||
if (packed) {
|
||||
ZEND_ASSERT(HT_IS_PACKED(ht));
|
||||
if (nSize > ht->nTableSize) {
|
||||
uint32_t newTableSize = zend_hash_check_size(nSize);
|
||||
HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_PACKED_SIZE_EX(newTableSize, HT_MIN_MASK), HT_PACKED_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT));
|
||||
uint32_t newTableSize = zend_hash_check_size(nSize, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!newTableSize)) {
|
||||
return FAILURE;
|
||||
}
|
||||
void *new_data = fperealloc2(HT_GET_DATA_ADDR(ht), HT_PACKED_SIZE_EX(newTableSize, HT_MIN_MASK), HT_PACKED_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!new_data)) {
|
||||
return FAILURE;
|
||||
}
|
||||
HT_SET_DATA_ADDR(ht, new_data);
|
||||
ht->nTableSize = newTableSize;
|
||||
}
|
||||
} else {
|
||||
@@ -417,8 +554,14 @@ ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool
|
||||
if (nSize > ht->nTableSize) {
|
||||
void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
|
||||
Bucket *old_buckets = ht->arData;
|
||||
nSize = zend_hash_check_size(nSize);
|
||||
new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
|
||||
nSize = zend_hash_check_size(nSize, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!nSize)) {
|
||||
return FAILURE;
|
||||
}
|
||||
new_data = fpemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!new_data)) {
|
||||
return FAILURE;
|
||||
}
|
||||
ht->nTableSize = nSize;
|
||||
ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
|
||||
HT_SET_DATA_ADDR(ht, new_data);
|
||||
@@ -428,6 +571,18 @@ ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_API zend_result ZEND_FASTCALL zend_hash_fextend(HashTable *ht, uint32_t nSize, bool packed)
|
||||
{
|
||||
return _zend_hash_fextend(ht, nSize, packed, /* fallible */ true);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool packed)
|
||||
{
|
||||
_zend_hash_fextend(ht, nSize, packed, /* fallible */ false);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_discard(HashTable *ht, uint32_t nNumUsed)
|
||||
@@ -832,10 +987,16 @@ static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_s
|
||||
|
||||
if (UNEXPECTED(HT_FLAGS(ht) & (HASH_FLAG_UNINITIALIZED|HASH_FLAG_PACKED))) {
|
||||
if (EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
|
||||
zend_hash_real_init_mixed(ht);
|
||||
zend_result status = zend_hash_real_finit_mixed(ht, flag & HASH_FALLIBLE);
|
||||
if (ZEND_CONST_COND(flag & HASH_FALLIBLE, true) && UNEXPECTED(status == FAILURE)) {
|
||||
return HASH_NOMEM;
|
||||
}
|
||||
goto add_to_hash;
|
||||
} else {
|
||||
zend_hash_packed_to_hash(ht);
|
||||
zend_result status = zend_hash_fconvert_packed_to_hash(ht, flag & HASH_FALLIBLE);
|
||||
if (ZEND_CONST_COND(flag & HASH_FALLIBLE, true) && UNEXPECTED(status == FAILURE)) {
|
||||
return HASH_NOMEM;
|
||||
}
|
||||
}
|
||||
} else if ((flag & HASH_ADD_NEW) == 0 || ZEND_DEBUG) {
|
||||
p = zend_hash_find_bucket(ht, key);
|
||||
@@ -1004,6 +1165,11 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key, z
|
||||
return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_fupdate(HashTable *ht, zend_string *key, zval *pData)
|
||||
{
|
||||
return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_FALLIBLE);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_update_ind(HashTable *ht, zend_string *key, zval *pData)
|
||||
{
|
||||
return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT);
|
||||
@@ -1014,11 +1180,21 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key,
|
||||
return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_fadd_new(HashTable *ht, zend_string *key, zval *pData)
|
||||
{
|
||||
return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW | HASH_FALLIBLE);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key)
|
||||
{
|
||||
return _zend_hash_add_or_update_i(ht, key, NULL, HASH_LOOKUP);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_flookup(HashTable *ht, zend_string *key)
|
||||
{
|
||||
return _zend_hash_add_or_update_i(ht, key, NULL, HASH_LOOKUP | HASH_FALLIBLE);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_or_update(HashTable *ht, const char *str, size_t len, zval *pData, uint32_t flag)
|
||||
{
|
||||
if (flag == HASH_ADD) {
|
||||
@@ -1112,7 +1288,10 @@ static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht,
|
||||
zv = ht->arPacked + h;
|
||||
if (flag & HASH_ADD_NEW) {
|
||||
ZEND_ASSERT(Z_TYPE_P(zv) == IS_UNDEF);
|
||||
goto convert_to_hash;
|
||||
zend_result status = zend_hash_fconvert_packed_to_hash(ht, flag & HASH_FALLIBLE);
|
||||
if (ZEND_CONST_COND(flag & HASH_FALLIBLE, true) && UNEXPECTED(status == FAILURE)) {
|
||||
return HASH_NOMEM;
|
||||
}
|
||||
} else if (Z_TYPE_P(zv) != IS_UNDEF) {
|
||||
if (flag & HASH_LOOKUP) {
|
||||
return zv;
|
||||
@@ -1127,7 +1306,10 @@ replace:
|
||||
ZVAL_COPY_VALUE(zv, pData);
|
||||
return zv;
|
||||
} else { /* we have to keep the order :( */
|
||||
goto convert_to_hash;
|
||||
zend_result status = zend_hash_fconvert_packed_to_hash(ht, flag & HASH_FALLIBLE);
|
||||
if (ZEND_CONST_COND(flag & HASH_FALLIBLE, true) && UNEXPECTED(status == FAILURE)) {
|
||||
return HASH_NOMEM;
|
||||
}
|
||||
}
|
||||
} else if (EXPECTED(h < ht->nTableSize)) {
|
||||
add_to_packed:
|
||||
@@ -1153,21 +1335,34 @@ add_to_packed:
|
||||
return zv;
|
||||
} else if ((h >> 1) < ht->nTableSize &&
|
||||
(ht->nTableSize >> 1) < ht->nNumOfElements) {
|
||||
zend_hash_packed_grow(ht);
|
||||
zend_result status = zend_hash_packed_fgrow(ht, flag & HASH_FALLIBLE);
|
||||
if (ZEND_CONST_COND(flag & HASH_FALLIBLE, true) && UNEXPECTED(status == FAILURE)) {
|
||||
return HASH_NOMEM;
|
||||
}
|
||||
goto add_to_packed;
|
||||
} else {
|
||||
uint32_t origSize = ht->nTableSize;
|
||||
if (ht->nNumUsed >= ht->nTableSize) {
|
||||
ht->nTableSize += ht->nTableSize;
|
||||
}
|
||||
convert_to_hash:
|
||||
zend_hash_packed_to_hash(ht);
|
||||
zend_result status = zend_hash_fconvert_packed_to_hash(ht, flag & HASH_FALLIBLE);
|
||||
if (ZEND_CONST_COND(flag & HASH_FALLIBLE, true) && UNEXPECTED(status == FAILURE)) {
|
||||
ht->nTableSize = origSize;
|
||||
return HASH_NOMEM;
|
||||
}
|
||||
}
|
||||
} else if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
|
||||
if (h < ht->nTableSize) {
|
||||
zend_hash_real_init_packed_ex(ht);
|
||||
zend_result status = zend_hash_real_finit_packed_ex(ht, flag & HASH_FALLIBLE);
|
||||
if (ZEND_CONST_COND(flag & HASH_FALLIBLE, true) && UNEXPECTED(status == FAILURE)) {
|
||||
return HASH_NOMEM;
|
||||
}
|
||||
goto add_to_packed;
|
||||
}
|
||||
zend_hash_real_init_mixed(ht);
|
||||
zend_result status = zend_hash_real_finit_mixed(ht, flag & HASH_FALLIBLE);
|
||||
if (ZEND_CONST_COND(flag & HASH_FALLIBLE, true) && UNEXPECTED(status == FAILURE)) {
|
||||
return HASH_NOMEM;
|
||||
}
|
||||
} else {
|
||||
if ((flag & HASH_ADD_NEW) == 0 || ZEND_DEBUG) {
|
||||
p = zend_hash_index_find_bucket(ht, h);
|
||||
@@ -1236,21 +1431,41 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h,
|
||||
return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_UPDATE);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_index_fupdate(HashTable *ht, zend_ulong h, zval *pData)
|
||||
{
|
||||
return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_UPDATE | HASH_FALLIBLE);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData)
|
||||
{
|
||||
return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEXT);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_finsert(HashTable *ht, zval *pData)
|
||||
{
|
||||
return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEXT | HASH_FALLIBLE);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval *pData)
|
||||
{
|
||||
return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEW | HASH_ADD_NEXT);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_finsert_new(HashTable *ht, zval *pData)
|
||||
{
|
||||
return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEW | HASH_ADD_NEXT | HASH_FALLIBLE);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h)
|
||||
{
|
||||
return _zend_hash_index_add_or_update_i(ht, h, NULL, HASH_LOOKUP);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_index_flookup(HashTable *ht, zend_ulong h)
|
||||
{
|
||||
return _zend_hash_index_add_or_update_i(ht, h, NULL, HASH_LOOKUP | HASH_FALLIBLE);
|
||||
}
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *b, zend_string *key)
|
||||
{
|
||||
uint32_t nIndex;
|
||||
@@ -1312,9 +1527,8 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *b,
|
||||
return &b->val;
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
|
||||
static zend_result ZEND_FASTCALL zend_hash_do_fresize(HashTable *ht, bool fallible)
|
||||
{
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
HT_ASSERT_RC1(ht);
|
||||
|
||||
@@ -1328,7 +1542,10 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
|
||||
|
||||
ZEND_ASSERT(HT_SIZE_TO_MASK(nSize) != 0);
|
||||
|
||||
new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
|
||||
new_data = fpemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!new_data)) {
|
||||
return FAILURE;
|
||||
}
|
||||
ht->nTableSize = nSize;
|
||||
ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
|
||||
HT_SET_DATA_ADDR(ht, new_data);
|
||||
@@ -1336,8 +1553,10 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
|
||||
pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
|
||||
zend_hash_rehash(ht);
|
||||
} else {
|
||||
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket));
|
||||
zend_mm_delayed_error_or_panic(fallible, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket));
|
||||
return FAILURE;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht)
|
||||
|
||||
+57
-3
@@ -38,6 +38,7 @@ typedef enum {
|
||||
#define HASH_ADD_NEW (1<<3) /* Used when the offset is known not to exist. */
|
||||
#define HASH_ADD_NEXT (1<<4) /* Append to an array. (e.g. $array[] = 42;) */
|
||||
#define HASH_LOOKUP (1<<5) /* Look up an existing entry, or create one with a NULL value. */
|
||||
#define HASH_FALLIBLE (1<<6) /* Use fallible allocation. Return FAILURE or HASH_NOMEM when allocation fails (for functions with zend_result or zval* types, respectively). */
|
||||
|
||||
#define HASH_FLAG_CONSISTENCY ((1<<0) | (1<<1))
|
||||
#define HASH_FLAG_PACKED (1<<2)
|
||||
@@ -92,6 +93,7 @@ extern ZEND_API const HashTable zend_empty_array;
|
||||
Z_TYPE_INFO_P(__z) = IS_ARRAY; \
|
||||
} while (0)
|
||||
|
||||
#define HASH_NOMEM ((zval*)-1)
|
||||
|
||||
typedef struct _zend_hash_key {
|
||||
zend_ulong h;
|
||||
@@ -119,6 +121,11 @@ ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_discard(HashTable *ht, uint32_t nNumUsed);
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht);
|
||||
|
||||
ZEND_API zend_result ZEND_FASTCALL zend_hash_real_finit(HashTable *ht, bool packed, bool fallible);
|
||||
ZEND_API zend_result ZEND_FASTCALL zend_hash_real_finit_packed(HashTable *ht, bool fallible);
|
||||
ZEND_API zend_result ZEND_FASTCALL zend_hash_real_finit_mixed(HashTable *ht, bool fallible);
|
||||
ZEND_API zend_result ZEND_FASTCALL zend_hash_fextend(HashTable *ht, uint32_t nSize, bool packed);
|
||||
|
||||
/* additions/updates/changes */
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key,zval *pData);
|
||||
@@ -126,6 +133,9 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_update_ind(HashTable *ht, zend_string *ke
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_add(HashTable *ht, zend_string *key,zval *pData);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key,zval *pData);
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_fupdate(HashTable *ht, zend_string *key,zval *pData);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_fadd_new(HashTable *ht, zend_string *key,zval *pData);
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_or_update(HashTable *ht, const char *key, size_t len, zval *pData, uint32_t flag);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_str_update(HashTable *ht, const char *key, size_t len, zval *pData);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_str_update_ind(HashTable *ht, const char *key, size_t len, zval *pData);
|
||||
@@ -139,6 +149,10 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h,
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval *pData);
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_index_fupdate(HashTable *ht, zend_ulong h, zval *pData);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_finsert(HashTable *ht, zval *pData);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_finsert_new(HashTable *ht, zval *pData);
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_empty_element(HashTable *ht, const char *key, size_t len);
|
||||
@@ -219,6 +233,9 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_str_lookup(HashTable *ht, const char *str, size_t len);
|
||||
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_flookup(HashTable *ht, zend_string *key);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_index_flookup(HashTable *ht, zend_ulong h);
|
||||
|
||||
#define ZEND_HASH_INDEX_LOOKUP(_ht, _h, _ret) do { \
|
||||
if (EXPECTED(HT_IS_PACKED(_ht))) { \
|
||||
if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed)) { \
|
||||
@@ -341,12 +358,25 @@ ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht);
|
||||
: \
|
||||
_zend_new_array((size)) \
|
||||
)
|
||||
# define zend_fnew_array(size) \
|
||||
(__builtin_constant_p(size) ? \
|
||||
((((uint32_t)(size)) <= HT_MIN_SIZE) ? \
|
||||
_zend_fnew_array_0() \
|
||||
: \
|
||||
_zend_fnew_array((size)) \
|
||||
) \
|
||||
: \
|
||||
_zend_fnew_array((size)) \
|
||||
)
|
||||
#else
|
||||
# define zend_new_array(size) \
|
||||
_zend_new_array(size)
|
||||
# define zend_fnew_array(size) \
|
||||
_zend_fnew_array(size)
|
||||
#endif
|
||||
|
||||
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void);
|
||||
ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void);
|
||||
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size);
|
||||
ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(const zval *val1, const zval *val2);
|
||||
ZEND_API uint32_t zend_array_count(HashTable *ht);
|
||||
@@ -357,6 +387,9 @@ ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht);
|
||||
ZEND_API HashTable* ZEND_FASTCALL zend_symtable_to_proptable(HashTable *ht);
|
||||
ZEND_API HashTable* ZEND_FASTCALL zend_proptable_to_symtable(HashTable *ht, bool always_duplicate);
|
||||
|
||||
ZEND_API HashTable* ZEND_FASTCALL _zend_fnew_array_0(void);
|
||||
ZEND_API HashTable* ZEND_FASTCALL _zend_fnew_array(uint32_t size);
|
||||
|
||||
ZEND_API bool ZEND_FASTCALL _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx);
|
||||
|
||||
ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos);
|
||||
@@ -510,6 +543,16 @@ static zend_always_inline zval *zend_symtable_update(HashTable *ht, zend_string
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline zval *zend_symtable_fupdate(HashTable *ht, zend_string *key, zval *pData)
|
||||
{
|
||||
zend_ulong idx;
|
||||
|
||||
if (ZEND_HANDLE_NUMERIC(key, idx)) {
|
||||
return zend_hash_index_fupdate(ht, idx, pData);
|
||||
} else {
|
||||
return zend_hash_fupdate(ht, key, pData);
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline zval *zend_symtable_update_ind(HashTable *ht, zend_string *key, zval *pData)
|
||||
{
|
||||
@@ -522,7 +565,6 @@ static zend_always_inline zval *zend_symtable_update_ind(HashTable *ht, zend_str
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static zend_always_inline zend_result zend_symtable_del(HashTable *ht, zend_string *key)
|
||||
{
|
||||
zend_ulong idx;
|
||||
@@ -830,16 +872,28 @@ static zend_always_inline void *zend_hash_index_add_new_ptr(HashTable *ht, zend_
|
||||
return zv ? Z_PTR_P(zv) : NULL;
|
||||
}
|
||||
|
||||
static zend_always_inline void *zend_hash_index_update_ptr(HashTable *ht, zend_ulong h, void *pData)
|
||||
static zend_always_inline void *zend_hash_index_fupdate_ptr(HashTable *ht, zend_ulong h, void *pData, bool fallible)
|
||||
{
|
||||
zval tmp, *zv;
|
||||
|
||||
ZVAL_PTR(&tmp, pData);
|
||||
zv = zend_hash_index_update(ht, h, &tmp);
|
||||
if (fallible) {
|
||||
zv = zend_hash_index_fupdate(ht, h, &tmp);
|
||||
if (UNEXPECTED(zv == HASH_NOMEM)) {
|
||||
return HASH_NOMEM;
|
||||
}
|
||||
} else {
|
||||
zv = zend_hash_index_update(ht, h, &tmp);
|
||||
}
|
||||
ZEND_ASSERT(Z_PTR_P(zv));
|
||||
return Z_PTR_P(zv);
|
||||
}
|
||||
|
||||
static zend_always_inline void *zend_hash_index_update_ptr(HashTable *ht, zend_ulong h, void *pData)
|
||||
{
|
||||
return zend_hash_index_fupdate_ptr(ht, h, pData, /* fallible */ false);
|
||||
}
|
||||
|
||||
static zend_always_inline void *zend_hash_index_add_mem(HashTable *ht, zend_ulong h, void *pData, size_t size)
|
||||
{
|
||||
zval tmp, *zv;
|
||||
|
||||
+13
-1
@@ -115,7 +115,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
|
||||
zend_function *destructor = object->ce->destructor;
|
||||
|
||||
if (destructor) {
|
||||
if (UNEXPECTED(zend_object_is_lazy(object))) {
|
||||
if (UNEXPECTED(zend_object_is_lazy(object) || ZEND_HAS_OOM())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,6 +193,18 @@ ZEND_API zend_object* ZEND_FASTCALL zend_objects_new(zend_class_entry *ce)
|
||||
return object;
|
||||
}
|
||||
|
||||
ZEND_API zend_object* ZEND_FASTCALL zend_objects_fnew(zend_class_entry *ce)
|
||||
{
|
||||
zend_object *object = femalloc(sizeof(zend_object) + zend_object_properties_size(ce), /* fallible */ true);
|
||||
if (UNEXPECTED(!object)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_zend_object_std_init(object, ce);
|
||||
object->handlers = &std_object_handlers;
|
||||
return object;
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_object_set_properties_reinitable(zend_object *object, bool reinitable)
|
||||
{
|
||||
if (!ZEND_CLASS_HAS_READONLY_PROPS(object->ce)) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
BEGIN_EXTERN_C()
|
||||
ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class_entry *ce);
|
||||
ZEND_API zend_object* ZEND_FASTCALL zend_objects_new(zend_class_entry *ce);
|
||||
ZEND_API zend_object* ZEND_FASTCALL zend_objects_fnew(zend_class_entry *ce);
|
||||
ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, const zend_object *old_object);
|
||||
ZEND_API void ZEND_FASTCALL zend_object_set_properties_reinitable(zend_object *object, bool reinitable);
|
||||
|
||||
|
||||
+19
-3
@@ -3208,7 +3208,7 @@ ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup_ex(const char *source, size_t
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent) /* {{{ */
|
||||
static zend_always_inline zend_string* ZEND_FASTCALL _zend_string_ftolower_ex(zend_string *str, bool persistent, bool fallible)
|
||||
{
|
||||
size_t length = ZSTR_LEN(str);
|
||||
unsigned char *p = (unsigned char *) ZSTR_VAL(str);
|
||||
@@ -3219,7 +3219,10 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, boo
|
||||
while (p + BLOCKCONV_STRIDE <= end) {
|
||||
BLOCKCONV_LOAD(p);
|
||||
if (BLOCKCONV_FOUND()) {
|
||||
zend_string *res = zend_string_alloc(length, persistent);
|
||||
zend_string *res = zend_string_falloc(length, persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!res)) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str));
|
||||
unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));
|
||||
|
||||
@@ -3240,7 +3243,10 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, boo
|
||||
|
||||
while (p < end) {
|
||||
if (*p != zend_tolower_ascii(*p)) {
|
||||
zend_string *res = zend_string_alloc(length, persistent);
|
||||
zend_string *res = zend_string_falloc(length, persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!res)) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str));
|
||||
|
||||
unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));
|
||||
@@ -3255,8 +3261,18 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, boo
|
||||
|
||||
return zend_string_copy(str);
|
||||
}
|
||||
|
||||
ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent) /* {{{ */
|
||||
{
|
||||
return _zend_string_ftolower_ex(str, persistent, /* fallible */ false);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API zend_string* ZEND_FASTCALL zend_string_ftolower_ex(zend_string *str, bool persistent)
|
||||
{
|
||||
return _zend_string_ftolower_ex(str, persistent, /* fallible */ true);
|
||||
}
|
||||
|
||||
ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, bool persistent) /* {{{ */
|
||||
{
|
||||
size_t length = ZSTR_LEN(str);
|
||||
|
||||
@@ -487,6 +487,8 @@ ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup_ex(const char *source,
|
||||
ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent);
|
||||
ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, bool persistent);
|
||||
|
||||
ZEND_API zend_string* ZEND_FASTCALL zend_string_ftolower_ex(zend_string *str, bool persistent);
|
||||
|
||||
static zend_always_inline zend_string* zend_string_tolower(zend_string *str) {
|
||||
return zend_string_tolower_ex(str, false);
|
||||
}
|
||||
@@ -494,6 +496,10 @@ static zend_always_inline zend_string* zend_string_toupper(zend_string *str) {
|
||||
return zend_string_toupper_ex(str, false);
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string* zend_string_ftolower(zend_string *str) {
|
||||
return zend_string_ftolower_ex(str, false);
|
||||
}
|
||||
|
||||
ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2);
|
||||
ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length);
|
||||
ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2);
|
||||
|
||||
+55
-15
@@ -25,32 +25,72 @@
|
||||
#define SMART_STR_NEW_LEN(len) \
|
||||
(ZEND_MM_ALIGNED_SIZE_EX(len + SMART_STR_OVERHEAD, SMART_STR_PAGE) - SMART_STR_OVERHEAD)
|
||||
|
||||
ZEND_API void ZEND_FASTCALL smart_str_erealloc(smart_str *str, size_t len)
|
||||
static zend_always_inline bool i_smart_str_erealloc(smart_str *str, size_t len, bool fallible)
|
||||
{
|
||||
if (UNEXPECTED(!str->s)) {
|
||||
str->a = len <= SMART_STR_START_LEN
|
||||
size_t a = len <= SMART_STR_START_LEN
|
||||
? SMART_STR_START_LEN
|
||||
: SMART_STR_NEW_LEN(len);
|
||||
str->s = zend_string_alloc(str->a, 0);
|
||||
str->s = zend_string_falloc(a, /* persistent */ false, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && !str->s) {
|
||||
return false;
|
||||
}
|
||||
str->a = a;
|
||||
ZSTR_LEN(str->s) = 0;
|
||||
} else {
|
||||
str->a = SMART_STR_NEW_LEN(len);
|
||||
str->s = (zend_string *) erealloc2(str->s, str->a + _ZSTR_HEADER_SIZE + 1, _ZSTR_HEADER_SIZE + ZSTR_LEN(str->s));
|
||||
size_t a = SMART_STR_NEW_LEN(len);
|
||||
zend_string *s = (zend_string *) ferealloc2(str->s, a + _ZSTR_HEADER_SIZE + 1, _ZSTR_HEADER_SIZE + ZSTR_LEN(str->s), fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && !s) {
|
||||
return false;
|
||||
}
|
||||
str->a = a;
|
||||
str->s = s;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL smart_str_erealloc(smart_str *str, size_t len)
|
||||
{
|
||||
i_smart_str_erealloc(str, len, /* fallible */ false);
|
||||
}
|
||||
|
||||
ZEND_API bool ZEND_FASTCALL smart_str_ferealloc(smart_str *str, size_t len, bool fallible)
|
||||
{
|
||||
return i_smart_str_erealloc(str, len, fallible);
|
||||
}
|
||||
|
||||
static zend_always_inline bool i_smart_str_realloc(smart_str *str, size_t len, bool fallible)
|
||||
{
|
||||
if (UNEXPECTED(!str->s)) {
|
||||
size_t a = len <= SMART_STR_START_LEN
|
||||
? SMART_STR_START_LEN
|
||||
: SMART_STR_NEW_LEN(len);
|
||||
str->s = zend_string_falloc(a, /* persistent */ true, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && !str->s) {
|
||||
return false;
|
||||
}
|
||||
str->a = a;
|
||||
ZSTR_LEN(str->s) = 0;
|
||||
} else {
|
||||
size_t a = SMART_STR_NEW_LEN(len);
|
||||
zend_string *s = (zend_string *) safe_fperealloc(str->s, 1, a, _ZSTR_HEADER_SIZE + 1, /* persistent */ true, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && !s) {
|
||||
return false;
|
||||
}
|
||||
str->a = a;
|
||||
str->s = s;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL smart_str_realloc(smart_str *str, size_t len)
|
||||
{
|
||||
if (UNEXPECTED(!str->s)) {
|
||||
str->a = len <= SMART_STR_START_LEN
|
||||
? SMART_STR_START_LEN
|
||||
: SMART_STR_NEW_LEN(len);
|
||||
str->s = zend_string_alloc(str->a, 1);
|
||||
ZSTR_LEN(str->s) = 0;
|
||||
} else {
|
||||
str->a = SMART_STR_NEW_LEN(len);
|
||||
str->s = (zend_string *) perealloc(str->s, str->a + _ZSTR_HEADER_SIZE + 1, 1);
|
||||
}
|
||||
i_smart_str_realloc(str, len, /* fallible */ false);
|
||||
}
|
||||
|
||||
ZEND_API bool ZEND_FASTCALL smart_str_frealloc(smart_str *str, size_t len, bool fallible)
|
||||
{
|
||||
return i_smart_str_realloc(str, len, fallible);
|
||||
}
|
||||
|
||||
/* Windows uses VK_ESCAPE instead of \e */
|
||||
|
||||
+40
-7
@@ -22,7 +22,9 @@
|
||||
BEGIN_EXTERN_C()
|
||||
|
||||
ZEND_API void ZEND_FASTCALL smart_str_erealloc(smart_str *str, size_t len);
|
||||
ZEND_API bool ZEND_FASTCALL smart_str_ferealloc(smart_str *str, size_t len, bool fallible);
|
||||
ZEND_API void ZEND_FASTCALL smart_str_realloc(smart_str *str, size_t len);
|
||||
ZEND_API bool ZEND_FASTCALL smart_str_frealloc(smart_str *str, size_t len, bool fallible);
|
||||
ZEND_API void ZEND_FASTCALL smart_str_append_escaped(smart_str *str, const char *s, size_t l);
|
||||
/* If zero_fraction is true, then a ".0" will be added to numbers that would not otherwise
|
||||
* have a fractional part and look like integers. */
|
||||
@@ -35,7 +37,7 @@ ZEND_API void ZEND_FASTCALL smart_str_append_scalar(smart_str *str, const zval *
|
||||
ZEND_API zend_result ZEND_FASTCALL smart_str_append_zval(smart_str *dest, const zval *value, size_t truncate);
|
||||
END_EXTERN_C()
|
||||
|
||||
static zend_always_inline size_t smart_str_alloc(smart_str *str, size_t len, bool persistent) {
|
||||
static zend_always_inline size_t smart_str_falloc(smart_str *str, size_t len, bool persistent, bool fallible) {
|
||||
if (UNEXPECTED(!str->s)) {
|
||||
goto do_smart_str_realloc;
|
||||
} else {
|
||||
@@ -43,22 +45,44 @@ static zend_always_inline size_t smart_str_alloc(smart_str *str, size_t len, boo
|
||||
if (UNEXPECTED(len >= str->a)) {
|
||||
do_smart_str_realloc:
|
||||
if (persistent) {
|
||||
smart_str_realloc(str, len);
|
||||
bool success = smart_str_frealloc(str, len, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && !success) {
|
||||
ZEND_ASSERT(fallible);
|
||||
return (size_t)-1;
|
||||
}
|
||||
} else {
|
||||
smart_str_erealloc(str, len);
|
||||
bool success = smart_str_ferealloc(str, len, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && !success) {
|
||||
ZEND_ASSERT(fallible);
|
||||
return (size_t)-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static zend_always_inline char* smart_str_extend_ex(smart_str *dest, size_t len, bool persistent) {
|
||||
size_t new_len = smart_str_alloc(dest, len, persistent);
|
||||
static zend_always_inline size_t smart_str_alloc(smart_str *str, size_t len, bool persistent) {
|
||||
size_t result = smart_str_falloc(str, len, persistent, /* fallible */ false);
|
||||
ZEND_ASSERT(result != (size_t)-1);
|
||||
return result;
|
||||
}
|
||||
|
||||
static zend_always_inline char* smart_str_fextend_ex(smart_str *dest, size_t len, bool persistent, bool fallible) {
|
||||
size_t new_len = smart_str_falloc(dest, len, persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && new_len == (size_t)-1) {
|
||||
return NULL;
|
||||
}
|
||||
ZEND_ASSERT(new_len != (size_t)-1);
|
||||
char *ret = ZSTR_VAL(dest->s) + ZSTR_LEN(dest->s);
|
||||
ZSTR_LEN(dest->s) = new_len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static zend_always_inline char* smart_str_extend_ex(smart_str *dest, size_t len, bool persistent) {
|
||||
return smart_str_fextend_ex(dest, len, persistent, /* fallible */ false);
|
||||
}
|
||||
|
||||
static zend_always_inline char* smart_str_extend(smart_str *dest, size_t length)
|
||||
{
|
||||
return smart_str_extend_ex(dest, length, false);
|
||||
@@ -124,10 +148,19 @@ static zend_always_inline void smart_str_appendc_ex(smart_str *dest, char ch, bo
|
||||
ZSTR_LEN(dest->s) = new_len;
|
||||
}
|
||||
|
||||
static zend_always_inline void smart_str_appendl_ex(smart_str *dest, const char *str, size_t len, bool persistent) {
|
||||
size_t new_len = smart_str_alloc(dest, len, persistent);
|
||||
static zend_always_inline bool smart_str_fappendl_ex(smart_str *dest, const char *str, size_t len, bool persistent, bool fallible) {
|
||||
size_t new_len = smart_str_falloc(dest, len, persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && new_len == (size_t)-1) {
|
||||
return false;
|
||||
}
|
||||
ZEND_ASSERT(new_len != (size_t)-1);
|
||||
memcpy(ZSTR_VAL(dest->s) + ZSTR_LEN(dest->s), str, len);
|
||||
ZSTR_LEN(dest->s) = new_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static zend_always_inline void smart_str_appendl_ex(smart_str *dest, const char *str, size_t len, bool persistent) {
|
||||
smart_str_fappendl_ex(dest, str, len, persistent, /* fallible */ false);
|
||||
}
|
||||
|
||||
static zend_always_inline void smart_str_append_ex(smart_str *dest, const zend_string *src, bool persistent) {
|
||||
|
||||
+20
-2
@@ -155,6 +155,18 @@ ZEND_API void zend_interned_strings_dtor(void)
|
||||
zend_known_strings = NULL;
|
||||
}
|
||||
|
||||
ZEND_API zend_string* ZEND_FASTCALL zend_string_finit_existing_interned(const char *str, size_t len, bool permanent, bool fallible)
|
||||
{
|
||||
bool was_fallible = CG(interned_strings_fallible);
|
||||
CG(interned_strings_fallible) = fallible;
|
||||
|
||||
zend_string *ret = zend_string_init_existing_interned(str, len, permanent);
|
||||
|
||||
CG(interned_strings_fallible) = was_fallible;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_interned_string_ht_lookup_ex(zend_ulong h, const char *str, size_t size, HashTable *interned_strings)
|
||||
{
|
||||
uint32_t nIndex;
|
||||
@@ -315,7 +327,10 @@ static zend_string* ZEND_FASTCALL zend_string_init_existing_interned_permanent(c
|
||||
}
|
||||
|
||||
ZEND_ASSERT(permanent);
|
||||
ret = zend_string_init(str, size, permanent);
|
||||
ret = zend_string_finit(str, size, permanent, CG(interned_strings_fallible));
|
||||
if (UNEXPECTED(!ret)) {
|
||||
return NULL;
|
||||
}
|
||||
ZSTR_H(ret) = h;
|
||||
return ret;
|
||||
}
|
||||
@@ -364,7 +379,10 @@ static zend_string* ZEND_FASTCALL zend_string_init_existing_interned_request(con
|
||||
}
|
||||
|
||||
ZEND_ASSERT(!permanent);
|
||||
ret = zend_string_init(str, size, permanent);
|
||||
ret = zend_string_finit(str, size, permanent, CG(interned_strings_fallible));
|
||||
if (UNEXPECTED(!ret)) {
|
||||
return NULL;
|
||||
}
|
||||
ZSTR_H(ret) = h;
|
||||
return ret;
|
||||
}
|
||||
|
||||
+115
-35
@@ -43,6 +43,7 @@ ZEND_API extern zend_string_init_existing_interned_func_t zend_string_init_exist
|
||||
ZEND_API zend_ulong ZEND_FASTCALL zend_string_hash_func(zend_string *str);
|
||||
ZEND_API zend_ulong ZEND_FASTCALL zend_hash_func(const char *str, size_t len);
|
||||
ZEND_API zend_string* ZEND_FASTCALL zend_interned_string_find_permanent(zend_string *str);
|
||||
ZEND_API zend_string* ZEND_FASTCALL zend_string_finit_existing_interned(const char *str, size_t len, bool permanent, bool fallible);
|
||||
ZEND_API void ZEND_FASTCALL zend_bin2hex(char *out, const unsigned char *in, size_t in_len);
|
||||
ZEND_API zend_string *zend_bin2hex_str(const unsigned char *in, size_t in_len);
|
||||
|
||||
@@ -185,9 +186,13 @@ static zend_always_inline uint32_t zend_string_delref(zend_string *s)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_alloc(size_t len, bool persistent)
|
||||
/* Fallible variant of zend_string_alloc */
|
||||
static zend_always_inline zend_string *zend_string_falloc(size_t len, bool persistent, bool fallible)
|
||||
{
|
||||
zend_string *ret = (zend_string *)pemalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
|
||||
zend_string *ret = (zend_string *)fpemalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(ret == NULL)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
GC_SET_REFCOUNT(ret, 1);
|
||||
GC_TYPE_INFO(ret) = GC_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << GC_FLAGS_SHIFT);
|
||||
@@ -196,9 +201,18 @@ static zend_always_inline zend_string *zend_string_alloc(size_t len, bool persis
|
||||
return ret;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_safe_alloc(size_t n, size_t m, size_t l, bool persistent)
|
||||
static zend_always_inline zend_string *zend_string_alloc(size_t len, bool persistent)
|
||||
{
|
||||
zend_string *ret = (zend_string *)safe_pemalloc(n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent);
|
||||
return zend_string_falloc(len, persistent, /* fallible */ false);
|
||||
}
|
||||
|
||||
/* Fallible variant of zend_string_safe_alloc */
|
||||
static zend_always_inline zend_string *zend_string_safe_falloc(size_t n, size_t m, size_t l, bool persistent, bool fallible)
|
||||
{
|
||||
zend_string *ret = (zend_string *)safe_fpemalloc(n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(ret == NULL)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
GC_SET_REFCOUNT(ret, 1);
|
||||
GC_TYPE_INFO(ret) = GC_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << GC_FLAGS_SHIFT);
|
||||
@@ -207,6 +221,11 @@ static zend_always_inline zend_string *zend_string_safe_alloc(size_t n, size_t m
|
||||
return ret;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_safe_alloc(size_t n, size_t m, size_t l, bool persistent)
|
||||
{
|
||||
return zend_string_safe_falloc(n, m, l, persistent, /* fallible */ false);
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_init(const char *str, size_t len, bool persistent)
|
||||
{
|
||||
zend_string *ret = zend_string_alloc(len, persistent);
|
||||
@@ -216,10 +235,22 @@ static zend_always_inline zend_string *zend_string_init(const char *str, size_t
|
||||
return ret;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_init_fast(const char *str, size_t len)
|
||||
static zend_always_inline zend_string *zend_string_finit(const char *str, size_t len, bool persistent, bool fallible)
|
||||
{
|
||||
zend_string *ret = zend_string_safe_falloc(len, 1, 0, persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(ret == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(ZSTR_VAL(ret), str, len);
|
||||
ZSTR_VAL(ret)[len] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_finit_fast(const char *str, size_t len, bool fallible)
|
||||
{
|
||||
if (len > 1) {
|
||||
return zend_string_init(str, len, 0);
|
||||
return zend_string_finit(str, len, 0, fallible);
|
||||
} else if (len == 0) {
|
||||
return zend_empty_string;
|
||||
} else /* if (len == 1) */ {
|
||||
@@ -227,6 +258,11 @@ static zend_always_inline zend_string *zend_string_init_fast(const char *str, si
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_init_fast(const char *str, size_t len)
|
||||
{
|
||||
return zend_string_finit_fast(str, len, /* fallible */ false);
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_copy(zend_string *s)
|
||||
{
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
@@ -257,19 +293,25 @@ static zend_always_inline zend_string *zend_string_separate(zend_string *s, bool
|
||||
return s;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_realloc(zend_string *s, size_t len, bool persistent)
|
||||
static zend_always_inline zend_string *zend_string_frealloc(zend_string *s, size_t len, bool persistent, bool fallible)
|
||||
{
|
||||
zend_string *ret;
|
||||
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
if (EXPECTED(GC_REFCOUNT(s) == 1)) {
|
||||
ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
|
||||
ret = (zend_string *)safe_fperealloc(s, 1, len, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(0)), persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!ret)) {
|
||||
return NULL;
|
||||
}
|
||||
ZSTR_LEN(ret) = len;
|
||||
zend_string_forget_hash_val(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = zend_string_alloc(len, persistent);
|
||||
ret = zend_string_falloc(len, persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!ret)) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN(len, ZSTR_LEN(s)) + 1);
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
GC_DELREF(s);
|
||||
@@ -277,21 +319,64 @@ static zend_always_inline zend_string *zend_string_realloc(zend_string *s, size_
|
||||
return ret;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_realloc(zend_string *s, size_t len, bool persistent)
|
||||
{
|
||||
return zend_string_frealloc(s, len, persistent, /* fallible */ false);
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_fextend(zend_string *s, size_t len, bool persistent, bool fallible)
|
||||
{
|
||||
zend_string *ret;
|
||||
|
||||
ZEND_ASSERT(len >= ZSTR_LEN(s));
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
if (EXPECTED(GC_REFCOUNT(s) == 1)) {
|
||||
ret = (zend_string *)safe_fperealloc(s, 1, len, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(0)), persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!ret)) {
|
||||
return NULL;
|
||||
}
|
||||
ZSTR_LEN(ret) = len;
|
||||
zend_string_forget_hash_val(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = zend_string_falloc(len, persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!ret)) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), ZSTR_LEN(s) + 1);
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
GC_DELREF(s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_extend(zend_string *s, size_t len, bool persistent)
|
||||
{
|
||||
return zend_string_fextend(s, len, persistent, /* fallible */ false);
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_ftruncate(zend_string *s, size_t len, bool persistent, bool fallible)
|
||||
{
|
||||
zend_string *ret;
|
||||
|
||||
ZEND_ASSERT(len >= ZSTR_LEN(s));
|
||||
ZEND_ASSERT(len <= ZSTR_LEN(s));
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
if (EXPECTED(GC_REFCOUNT(s) == 1)) {
|
||||
ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
|
||||
ret = (zend_string *)safe_fperealloc(s, 1, len, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(0)), persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!ret)) {
|
||||
return NULL;
|
||||
}
|
||||
ZSTR_LEN(ret) = len;
|
||||
zend_string_forget_hash_val(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = zend_string_alloc(len, persistent);
|
||||
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), ZSTR_LEN(s) + 1);
|
||||
ret = zend_string_falloc(len, persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(!ret)) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), len + 1);
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
GC_DELREF(s);
|
||||
}
|
||||
@@ -299,20 +384,30 @@ static zend_always_inline zend_string *zend_string_extend(zend_string *s, size_t
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_truncate(zend_string *s, size_t len, bool persistent)
|
||||
{
|
||||
return zend_string_ftruncate(s, len, persistent, /*fallible */ false);
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_safe_frealloc(zend_string *s, size_t n, size_t m, size_t l, bool persistent, bool fallible)
|
||||
{
|
||||
zend_string *ret;
|
||||
|
||||
ZEND_ASSERT(len <= ZSTR_LEN(s));
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
if (EXPECTED(GC_REFCOUNT(s) == 1)) {
|
||||
ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
|
||||
ZSTR_LEN(ret) = len;
|
||||
if (GC_REFCOUNT(s) == 1) {
|
||||
ret = (zend_string *)safe_fperealloc(s, n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && !ret) {
|
||||
return NULL;
|
||||
}
|
||||
ZSTR_LEN(ret) = (n * m) + l;
|
||||
zend_string_forget_hash_val(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = zend_string_alloc(len, persistent);
|
||||
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), len + 1);
|
||||
ret = zend_string_safe_falloc(n, m, l, persistent, fallible);
|
||||
if (ZEND_CONST_COND(fallible, true) && !ret) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN((n * m) + l, ZSTR_LEN(s)) + 1);
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
GC_DELREF(s);
|
||||
}
|
||||
@@ -321,22 +416,7 @@ static zend_always_inline zend_string *zend_string_truncate(zend_string *s, size
|
||||
|
||||
static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s, size_t n, size_t m, size_t l, bool persistent)
|
||||
{
|
||||
zend_string *ret;
|
||||
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
if (GC_REFCOUNT(s) == 1) {
|
||||
ret = (zend_string *)safe_perealloc(s, n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent);
|
||||
ZSTR_LEN(ret) = (n * m) + l;
|
||||
zend_string_forget_hash_val(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = zend_string_safe_alloc(n, m, l, persistent);
|
||||
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN((n * m) + l, ZSTR_LEN(s)) + 1);
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
GC_DELREF(s);
|
||||
}
|
||||
return ret;
|
||||
return zend_string_safe_frealloc(s, n, m, l, persistent, /* fallible */ false);
|
||||
}
|
||||
|
||||
static zend_always_inline char *zend_cstr_append_char(const char *str, size_t len, char c) {
|
||||
|
||||
+42
-30
@@ -525,38 +525,50 @@ static zend_always_inline void HT_HASH_RESET(HashTable *ht) {
|
||||
size_t size = HT_HASH_SIZE(ht->nTableMask);
|
||||
|
||||
#if defined(__AVX2__)
|
||||
__m256i ymm0 = _mm256_setzero_si256();
|
||||
ymm0 = _mm256_cmpeq_epi64(ymm0, ymm0);
|
||||
ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
|
||||
do {
|
||||
_mm256_storeu_si256((__m256i*)p, ymm0);
|
||||
_mm256_storeu_si256((__m256i*)(p+32), ymm0);
|
||||
p += 64;
|
||||
size -= 64;
|
||||
} while (size != 0);
|
||||
if (UNEXPECTED(size < 64)) {
|
||||
memset(p, HT_INVALID_IDX, size);
|
||||
} else {
|
||||
__m256i ymm0 = _mm256_setzero_si256();
|
||||
ymm0 = _mm256_cmpeq_epi64(ymm0, ymm0);
|
||||
ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
|
||||
do {
|
||||
_mm256_storeu_si256((__m256i*)p, ymm0);
|
||||
_mm256_storeu_si256((__m256i*)(p+32), ymm0);
|
||||
p += 64;
|
||||
size -= 64;
|
||||
} while (size != 0);
|
||||
}
|
||||
#elif defined(__SSE2__)
|
||||
__m128i xmm0 = _mm_setzero_si128();
|
||||
xmm0 = _mm_cmpeq_epi8(xmm0, xmm0);
|
||||
ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
|
||||
do {
|
||||
_mm_storeu_si128((__m128i*)p, xmm0);
|
||||
_mm_storeu_si128((__m128i*)(p+16), xmm0);
|
||||
_mm_storeu_si128((__m128i*)(p+32), xmm0);
|
||||
_mm_storeu_si128((__m128i*)(p+48), xmm0);
|
||||
p += 64;
|
||||
size -= 64;
|
||||
} while (size != 0);
|
||||
if (UNEXPECTED(size < 64)) {
|
||||
memset(p, HT_INVALID_IDX, size);
|
||||
} else {
|
||||
__m128i xmm0 = _mm_setzero_si128();
|
||||
xmm0 = _mm_cmpeq_epi8(xmm0, xmm0);
|
||||
ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
|
||||
do {
|
||||
_mm_storeu_si128((__m128i*)p, xmm0);
|
||||
_mm_storeu_si128((__m128i*)(p+16), xmm0);
|
||||
_mm_storeu_si128((__m128i*)(p+32), xmm0);
|
||||
_mm_storeu_si128((__m128i*)(p+48), xmm0);
|
||||
p += 64;
|
||||
size -= 64;
|
||||
} while (size != 0);
|
||||
}
|
||||
#elif defined(__aarch64__) || defined(_M_ARM64)
|
||||
int32x4_t t = vdupq_n_s32(-1);
|
||||
ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
|
||||
do {
|
||||
vst1q_s32((int32_t*)p, t);
|
||||
vst1q_s32((int32_t*)(p+16), t);
|
||||
vst1q_s32((int32_t*)(p+32), t);
|
||||
vst1q_s32((int32_t*)(p+48), t);
|
||||
p += 64;
|
||||
size -= 64;
|
||||
} while (size != 0);
|
||||
if (UNEXPECTED(size < 64)) {
|
||||
memset(p, HT_INVALID_IDX, size);
|
||||
} else {
|
||||
int32x4_t t = vdupq_n_s32(-1);
|
||||
ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
|
||||
do {
|
||||
vst1q_s32((int32_t*)p, t);
|
||||
vst1q_s32((int32_t*)(p+16), t);
|
||||
vst1q_s32((int32_t*)(p+32), t);
|
||||
vst1q_s32((int32_t*)(p+48), t);
|
||||
p += 64;
|
||||
size -= 64;
|
||||
} while (size != 0);
|
||||
}
|
||||
#else
|
||||
memset(p, HT_INVALID_IDX, size);
|
||||
#endif
|
||||
|
||||
+16
-6
@@ -3507,6 +3507,7 @@ ZEND_VM_HANDLER(56, ZEND_ROPE_END, TMP, CONST|TMP|CV, NUM)
|
||||
zval *var, *ret;
|
||||
uint32_t i;
|
||||
|
||||
SAVE_OPLINE();
|
||||
rope = (zend_string**)EX_VAR(opline->op1.var);
|
||||
if (OP2_TYPE == IS_CONST) {
|
||||
var = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
@@ -4149,7 +4150,7 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -4282,7 +4283,7 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER))
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -4415,7 +4416,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -8251,9 +8252,11 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
|
||||
{
|
||||
const zend_op *throw_op = EG(opline_before_exception);
|
||||
|
||||
/* Exception was thrown before executing any op */
|
||||
/* Exception was thrown before executing any op, or between two ops (see
|
||||
* zend_handle_delayed_oom()). */
|
||||
if (UNEXPECTED(!throw_op)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, -1, op_num, 0);
|
||||
free_unfinished_calls(execute_data);
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, -1, op_num, -1);
|
||||
}
|
||||
|
||||
uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes;
|
||||
@@ -9171,7 +9174,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER))
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -9970,6 +9973,7 @@ ZEND_VM_HANDLER(204, ZEND_FRAMELESS_ICALL_0, UNUSED, UNUSED, SPEC(OBSERVER))
|
||||
zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
|
||||
function(result);
|
||||
}
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -9996,6 +10000,7 @@ ZEND_VM_HANDLER(205, ZEND_FRAMELESS_ICALL_1, ANY, UNUSED, SPEC(OBSERVER))
|
||||
function(result, arg1);
|
||||
}
|
||||
FREE_OP1();
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -10030,6 +10035,7 @@ ZEND_VM_HANDLER(206, ZEND_FRAMELESS_ICALL_2, ANY, ANY, SPEC(OBSERVER))
|
||||
ZVAL_UNDEF(EX_VAR(opline->op1.var));
|
||||
}
|
||||
FREE_OP2();
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -10070,6 +10076,7 @@ ZEND_VM_HANDLER(207, ZEND_FRAMELESS_ICALL_3, ANY, ANY, SPEC(OBSERVER))
|
||||
ZVAL_UNDEF(EX_VAR(opline->op2.var));
|
||||
}
|
||||
FREE_OP_DATA();
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_EX(1, 2);
|
||||
}
|
||||
|
||||
@@ -10724,6 +10731,9 @@ ZEND_VM_HELPER(zend_interrupt_helper, ANY, ANY)
|
||||
#endif
|
||||
if (zend_atomic_bool_load_ex(&EG(timed_out))) {
|
||||
zend_timeout();
|
||||
} else if (ZEND_HAS_OOM()) {
|
||||
zend_handle_delayed_oom();
|
||||
HANDLE_EXCEPTION();
|
||||
} else if (zend_interrupt_function) {
|
||||
zend_interrupt_function(execute_data);
|
||||
if (EG(exception)) {
|
||||
|
||||
Generated
+58
-26
@@ -1323,7 +1323,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_D
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -1393,7 +1393,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_D
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -1463,7 +1463,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -1649,7 +1649,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_D
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -1767,7 +1767,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_D
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -1884,7 +1884,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -2020,7 +2020,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_D
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -2155,7 +2155,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_D
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -2287,7 +2287,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -3400,9 +3400,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_HANDLE_EXCEPT
|
||||
{
|
||||
const zend_op *throw_op = EG(opline_before_exception);
|
||||
|
||||
/* Exception was thrown before executing any op */
|
||||
/* Exception was thrown before executing any op, or between two ops (see
|
||||
* zend_handle_delayed_oom()). */
|
||||
if (UNEXPECTED(!throw_op)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX -1, 0));
|
||||
free_unfinished_calls(execute_data);
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX -1, -1));
|
||||
}
|
||||
|
||||
uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes;
|
||||
@@ -3676,7 +3678,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_CALL_TRAMPOLI
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -3824,7 +3826,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_CALL_TRAMPOLI
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -3905,6 +3907,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FRAMELESS_ICA
|
||||
ZVAL_UNDEF(EX_VAR(opline->op1.var));
|
||||
}
|
||||
FREE_OP(opline->op2_type, opline->op2.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -3939,6 +3942,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FRAMELESS_ICA
|
||||
ZVAL_UNDEF(EX_VAR(opline->op1.var));
|
||||
}
|
||||
FREE_OP(opline->op2_type, opline->op2.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -3979,6 +3983,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FRAMELESS_ICA
|
||||
ZVAL_UNDEF(EX_VAR(opline->op2.var));
|
||||
}
|
||||
FREE_OP((opline+1)->op1_type, (opline+1)->op1.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_EX(1, 2);
|
||||
}
|
||||
|
||||
@@ -4019,6 +4024,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FRAMELESS_ICA
|
||||
ZVAL_UNDEF(EX_VAR(opline->op2.var));
|
||||
}
|
||||
FREE_OP((opline+1)->op1_type, (opline+1)->op1.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_EX(1, 2);
|
||||
}
|
||||
|
||||
@@ -4041,6 +4047,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV
|
||||
#endif
|
||||
if (zend_atomic_bool_load_ex(&EG(timed_out))) {
|
||||
zend_timeout();
|
||||
} else if (ZEND_HAS_OOM()) {
|
||||
zend_handle_delayed_oom();
|
||||
HANDLE_EXCEPTION();
|
||||
} else if (zend_interrupt_function) {
|
||||
zend_interrupt_function(execute_data);
|
||||
if (EG(exception)) {
|
||||
@@ -4440,6 +4449,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FRAMELESS_ICA
|
||||
function(result, arg1);
|
||||
}
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -4466,6 +4476,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FRAMELESS_ICA
|
||||
function(result, arg1);
|
||||
}
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -19126,6 +19137,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ROPE_END_SPEC
|
||||
zval *var, *ret;
|
||||
uint32_t i;
|
||||
|
||||
SAVE_OPLINE();
|
||||
rope = (zend_string**)EX_VAR(opline->op1.var);
|
||||
if (IS_CONST == IS_CONST) {
|
||||
var = RT_CONSTANT(opline, opline->op2);
|
||||
@@ -20706,6 +20718,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ROPE_END_SPEC
|
||||
zval *var, *ret;
|
||||
uint32_t i;
|
||||
|
||||
SAVE_OPLINE();
|
||||
rope = (zend_string**)EX_VAR(opline->op1.var);
|
||||
if (IS_TMP_VAR == IS_CONST) {
|
||||
var = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC);
|
||||
@@ -22563,6 +22576,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ROPE_END_SPEC
|
||||
zval *var, *ret;
|
||||
uint32_t i;
|
||||
|
||||
SAVE_OPLINE();
|
||||
rope = (zend_string**)EX_VAR(opline->op1.var);
|
||||
if (IS_CV == IS_CONST) {
|
||||
var = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC);
|
||||
@@ -37717,6 +37731,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FRAMELESS_ICA
|
||||
zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
|
||||
function(result);
|
||||
}
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -37737,6 +37752,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FRAMELESS_ICA
|
||||
zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
|
||||
function(result);
|
||||
}
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -54302,7 +54318,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_ICA
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -54372,7 +54388,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_ICA
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -54442,7 +54458,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_IC
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -54628,7 +54644,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_FCA
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -54746,7 +54762,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_FCA
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -54863,7 +54879,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_FC
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -54999,7 +55015,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_FCA
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -55134,7 +55150,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_FCA
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -55266,7 +55282,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_FC
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func && !(call->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -56263,9 +56279,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_HANDLE_EXCEPTION_S
|
||||
{
|
||||
const zend_op *throw_op = EG(opline_before_exception);
|
||||
|
||||
/* Exception was thrown before executing any op */
|
||||
/* Exception was thrown before executing any op, or between two ops (see
|
||||
* zend_handle_delayed_oom()). */
|
||||
if (UNEXPECTED(!throw_op)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper_SPEC_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX -1, 0));
|
||||
free_unfinished_calls(execute_data);
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper_SPEC_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX -1, -1));
|
||||
}
|
||||
|
||||
uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes;
|
||||
@@ -56539,7 +56557,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_CALL_TRAMPOLINE_SP
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -56687,7 +56705,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_CALL_TRAMPOLINE_SP
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (!EG(exception) && call->func) {
|
||||
if (!EG(exception) && !ZEND_HAS_OOM() && call->func) {
|
||||
if (should_throw) {
|
||||
zend_internal_call_arginfo_violation(call->func);
|
||||
}
|
||||
@@ -56768,6 +56786,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FRAMELESS_ICALL_2_
|
||||
ZVAL_UNDEF(EX_VAR(opline->op1.var));
|
||||
}
|
||||
FREE_OP(opline->op2_type, opline->op2.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -56802,6 +56821,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FRAMELESS_ICALL_2_
|
||||
ZVAL_UNDEF(EX_VAR(opline->op1.var));
|
||||
}
|
||||
FREE_OP(opline->op2_type, opline->op2.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -56842,6 +56862,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FRAMELESS_ICALL_3_
|
||||
ZVAL_UNDEF(EX_VAR(opline->op2.var));
|
||||
}
|
||||
FREE_OP((opline+1)->op1_type, (opline+1)->op1.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_EX(1, 2);
|
||||
}
|
||||
|
||||
@@ -56882,6 +56903,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FRAMELESS_ICALL_3_
|
||||
ZVAL_UNDEF(EX_VAR(opline->op2.var));
|
||||
}
|
||||
FREE_OP((opline+1)->op1_type, (opline+1)->op1.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_EX(1, 2);
|
||||
}
|
||||
|
||||
@@ -56904,6 +56926,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend
|
||||
#endif
|
||||
if (zend_atomic_bool_load_ex(&EG(timed_out))) {
|
||||
zend_timeout();
|
||||
} else if (ZEND_HAS_OOM()) {
|
||||
zend_handle_delayed_oom();
|
||||
HANDLE_EXCEPTION();
|
||||
} else if (zend_interrupt_function) {
|
||||
zend_interrupt_function(execute_data);
|
||||
if (EG(exception)) {
|
||||
@@ -57303,6 +57328,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FRAMELESS_ICALL_1_
|
||||
function(result, arg1);
|
||||
}
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -57329,6 +57355,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FRAMELESS_ICALL_1_
|
||||
function(result, arg1);
|
||||
}
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -71887,6 +71914,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ROPE_END_SPEC_TMP_
|
||||
zval *var, *ret;
|
||||
uint32_t i;
|
||||
|
||||
SAVE_OPLINE();
|
||||
rope = (zend_string**)EX_VAR(opline->op1.var);
|
||||
if (IS_CONST == IS_CONST) {
|
||||
var = RT_CONSTANT(opline, opline->op2);
|
||||
@@ -73467,6 +73495,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ROPE_END_SPEC_TMP_
|
||||
zval *var, *ret;
|
||||
uint32_t i;
|
||||
|
||||
SAVE_OPLINE();
|
||||
rope = (zend_string**)EX_VAR(opline->op1.var);
|
||||
if (IS_TMP_VAR == IS_CONST) {
|
||||
var = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC);
|
||||
@@ -75224,6 +75253,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ROPE_END_SPEC_TMP_
|
||||
zval *var, *ret;
|
||||
uint32_t i;
|
||||
|
||||
SAVE_OPLINE();
|
||||
rope = (zend_string**)EX_VAR(opline->op1.var);
|
||||
if (IS_CV == IS_CONST) {
|
||||
var = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC);
|
||||
@@ -90378,6 +90408,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FRAMELESS_ICALL_0_
|
||||
zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
|
||||
function(result);
|
||||
}
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -90398,6 +90429,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FRAMELESS_ICALL_0_
|
||||
zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
|
||||
function(result);
|
||||
}
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,4 +7,6 @@ bcmath
|
||||
bcmul('0', '0', 2147483647);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
|
||||
Hard memory limit of 268435456 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
|
||||
|
||||
Termsig=9
|
||||
+26
-5
@@ -513,7 +513,10 @@ PHP_FUNCTION(bzcompress)
|
||||
dest_len = (unsigned int) chunk_len;
|
||||
|
||||
/* Allocate the destination buffer */
|
||||
dest = zend_string_alloc(dest_len, 0);
|
||||
dest = zend_string_falloc(dest_len, 0, /* fallible */ true);
|
||||
if (!dest) {
|
||||
RETURN_OOM();
|
||||
}
|
||||
|
||||
int error = BZ2_bzBuffToBuffCompress(ZSTR_VAL(dest), &dest_len, source, source_len, block_size, 0, work_factor);
|
||||
if (error != BZ_OK) {
|
||||
@@ -533,7 +536,7 @@ PHP_FUNCTION(bzcompress)
|
||||
PHP_FUNCTION(bzdecompress)
|
||||
{
|
||||
char *source;
|
||||
zend_string *dest;
|
||||
zend_string *dest = NULL, *tmp;
|
||||
size_t source_len;
|
||||
int error;
|
||||
bool small = 0;
|
||||
@@ -560,7 +563,10 @@ PHP_FUNCTION(bzdecompress)
|
||||
bzs.avail_in = source_len;
|
||||
|
||||
/* in most cases bz2 offers at least 2:1 compression, so we use that as our base */
|
||||
dest = zend_string_safe_alloc(source_len, 2, 1, 0);
|
||||
dest = zend_string_safe_falloc(source_len, 2, 1, 0, /* fallible */ true);
|
||||
if (!dest) {
|
||||
goto failure;
|
||||
}
|
||||
bzs.avail_out = source_len * 2;
|
||||
bzs.next_out = ZSTR_VAL(dest);
|
||||
|
||||
@@ -572,7 +578,11 @@ PHP_FUNCTION(bzdecompress)
|
||||
/* no reason to continue if we're going to drop it anyway */
|
||||
break;
|
||||
}
|
||||
dest = zend_string_safe_realloc(dest, 1, (size_t) bzs.avail_out + 1, (size_t) size, 0);
|
||||
tmp = zend_string_safe_frealloc(dest, 1, (size_t) bzs.avail_out + 1, (size_t) size, 0, /* fallible */ true);
|
||||
if (!tmp) {
|
||||
goto failure;
|
||||
}
|
||||
dest = tmp;
|
||||
bzs.next_out = ZSTR_VAL(dest) + size;
|
||||
}
|
||||
|
||||
@@ -583,7 +593,11 @@ PHP_FUNCTION(bzdecompress)
|
||||
zend_string_efree(dest);
|
||||
RETVAL_LONG(BZ_MEM_ERROR);
|
||||
} else {
|
||||
dest = zend_string_safe_realloc(dest, 1, (size_t)size, 1, 0);
|
||||
tmp = zend_string_safe_frealloc(dest, 1, (size_t)size, 1, 0, /* fallible */ true);
|
||||
if (!tmp) {
|
||||
goto failure;
|
||||
}
|
||||
dest = tmp;
|
||||
ZSTR_LEN(dest) = (size_t)size;
|
||||
ZSTR_VAL(dest)[(size_t)size] = '\0';
|
||||
RETVAL_STR(dest);
|
||||
@@ -594,6 +608,13 @@ PHP_FUNCTION(bzdecompress)
|
||||
}
|
||||
|
||||
BZ2_bzDecompressEnd(&bzs);
|
||||
return;
|
||||
|
||||
failure:
|
||||
if (dest) {
|
||||
zend_string_efree(dest);
|
||||
}
|
||||
BZ2_bzDecompressEnd(&bzs);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
Loaded 100 of 424 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user