mirror of
https://github.com/php/php-src.git
synced 2026-10-28 17:56:50 +08:00
zend_object_alloc() zeroes the object, so cached_resize started at 0, which
spl_fixedarray_resize() reads as "resize in progress" and returns early.
setSize() therefore did nothing on subclasses whose constructor does not
call parent::__construct(). Initialise the struct on object creation.
setSize(0) clears the array before destroying its elements, so it looks
unconstructed to userland. __construct(), __wakeup() and __unserialize()
then re-initialised it, and the in-progress clear discarded the buffer
they had installed. cb3dc62fd9 fixed the same leak for a re-entrant
setSize() by testing the resize sentinel first; apply that test to the
other three entry points.
Close GH-23812
64 lines
1.5 KiB
PHP
64 lines
1.5 KiB
PHP
--TEST--
|
|
SplFixedArray: subclass not calling parent::__construct() (GH-23811)
|
|
--DESCRIPTION--
|
|
The internal struct is zeroed on object creation, which used to leave the
|
|
"resize in progress" sentinel at 0 instead of -1. setSize() then took the
|
|
re-entrancy early return and silently did nothing, leaving the array stuck
|
|
at size 0 for the lifetime of the object.
|
|
--FILE--
|
|
<?php
|
|
class Unconstructed extends SplFixedArray {
|
|
public function __construct() {
|
|
/* deliberately does not call parent::__construct() */
|
|
}
|
|
}
|
|
|
|
$a = new Unconstructed();
|
|
echo "initial: ", $a->getSize(), "\n";
|
|
|
|
$a->setSize(3);
|
|
echo "after setSize(3): ", $a->getSize(), "\n";
|
|
|
|
$a[0] = "x";
|
|
$a[2] = "z";
|
|
var_dump($a->toArray());
|
|
|
|
$a->setSize(1);
|
|
echo "after setSize(1): ", $a->getSize(), "\n";
|
|
|
|
$a->setSize(0);
|
|
echo "after setSize(0): ", $a->getSize(), "\n";
|
|
|
|
/* Deferred initialisation: calling the parent constructor later still works. */
|
|
class LateInit extends SplFixedArray {
|
|
public function __construct() {
|
|
}
|
|
public function init(int $size): void {
|
|
parent::__construct($size);
|
|
}
|
|
}
|
|
$b = new LateInit();
|
|
$b->init(2);
|
|
echo "deferred parent::__construct(2): ", $b->getSize(), "\n";
|
|
|
|
/* Cloning one of these must also yield a resizable array. */
|
|
$c = clone new Unconstructed();
|
|
$c->setSize(2);
|
|
echo "clone then setSize(2): ", $c->getSize(), "\n";
|
|
?>
|
|
--EXPECT--
|
|
initial: 0
|
|
after setSize(3): 3
|
|
array(3) {
|
|
[0]=>
|
|
string(1) "x"
|
|
[1]=>
|
|
NULL
|
|
[2]=>
|
|
string(1) "z"
|
|
}
|
|
after setSize(1): 1
|
|
after setSize(0): 0
|
|
deferred parent::__construct(2): 2
|
|
clone then setSize(2): 2
|