If the array is packed, then we don't have to loop to get the highest
index.
For this script:
```php
$array = range(1, 100);
for ($i=0;$i<1000000;$i++) {
SplFixedArray::fromArray($array);
}
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php spl.php
Time (mean ± σ): 376.5 ms ± 2.0 ms [User: 372.1 ms, System: 2.6 ms]
Range (min … max): 373.7 ms … 379.5 ms 10 runs
Benchmark 2: ./sapi/cli/php_old spl.php
Time (mean ± σ): 511.6 ms ± 1.9 ms [User: 508.0 ms, System: 2.3 ms]
Range (min … max): 509.2 ms … 515.1 ms 10 runs
Summary
./sapi/cli/php spl.php ran
1.36 ± 0.01 times faster than ./sapi/cli/php_old spl.php
```
On an i7-1185G7:
```
Benchmark 1: ./sapi/cli/php spl.php
Time (mean ± σ): 250.4 ms ± 3.5 ms [User: 246.6 ms, System: 2.6 ms]
Range (min … max): 247.0 ms … 258.5 ms 11 runs
Benchmark 2: ./sapi/cli/php_old spl.php
Time (mean ± σ): 328.4 ms ± 1.0 ms [User: 324.4 ms, System: 3.8 ms]
Range (min … max): 327.5 ms … 331.0 ms 10 runs
Summary
./sapi/cli/php spl.php ran
1.31 ± 0.02 times faster than ./sapi/cli/php_old spl.php
```
Bonus: this also decreases the code size of the function.
If there is not yet a dynamic property, and there are no class properties,
then we know that we don't have to build a properties table.
For this (micro-bench) script:
```php
function x() {
$fa = new SplFixedArray(1);
$fa[0] = $fa;
}
for ($i=0;$i<1000000;$i++)
x();
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php spl.php
Time (mean ± σ): 140.9 ms ± 1.2 ms [User: 137.5 ms, System: 2.7 ms]
Range (min … max): 138.9 ms … 144.9 ms 21 runs
Benchmark 2: ./sapi/cli/php_old spl.php
Time (mean ± σ): 162.0 ms ± 3.8 ms [User: 157.7 ms, System: 3.2 ms]
Range (min … max): 158.5 ms … 175.0 ms 17 runs
Summary
./sapi/cli/php spl.php ran
1.15 ± 0.03 times faster than ./sapi/cli/php_old spl.php
```
We can use the optimized packed filling code instead of going through
all the logic of the zend_hash update APIs.
For this script:
```php
$test = new SplFixedArray(4);
$test[0] = 0;
$test[1] = 1;
$test[2] = 2;
$test[3] = 3;
for ($i = 0 ; $i< 5000000; $i++)
$test->toArray();
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php toarray.php
Time (mean ± σ): 170.0 ms ± 1.8 ms [User: 167.3 ms, System: 2.2 ms]
Range (min … max): 166.9 ms … 173.0 ms 17 runs
Benchmark 2: ./sapi/cli/php_old toarray.php
Time (mean ± σ): 215.7 ms ± 3.6 ms [User: 211.9 ms, System: 3.0 ms]
Range (min … max): 211.3 ms … 222.0 ms 13 runs
Summary
./sapi/cli/php toarray.php ran
1.27 ± 0.02 times faster than ./sapi/cli/php_old toarray.php
```
On an i7-1185G7:
```
Benchmark 1: ./sapi/cli/php toarray.php
Time (mean ± σ): 112.6 ms ± 1.4 ms [User: 109.6 ms, System: 2.9 ms]
Range (min … max): 111.1 ms … 116.4 ms 25 runs
Benchmark 2: ./sapi/cli/php_old toarray.php
Time (mean ± σ): 145.3 ms ± 2.8 ms [User: 141.8 ms, System: 3.4 ms]
Range (min … max): 142.6 ms … 151.8 ms 20 runs
Summary
./sapi/cli/php toarray.php ran
1.29 ± 0.03 times faster than ./sapi/cli/php_old toarray.php
```
This patch optimizes reading and writing from SplFixedArray with the
dimension operators. It accomplishes this due to the following
optimizations:
* Fast-path for long keys (inlined).
* Optimization hints (UNEXPECTED + assertion)
* Using an unsigned index so we can do a single length comparison
For the following script:
```php
$test = new SplFixedArray(4);
for ($i = 0 ; $i< 5000000; $i++)
$test[1] += $i;
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 95.4 ms ± 1.6 ms [User: 91.5 ms, System: 3.2 ms]
Range (min … max): 93.7 ms … 100.8 ms 31 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 119.1 ms ± 1.3 ms [User: 114.7 ms, System: 3.6 ms]
Range (min … max): 117.6 ms … 123.1 ms 24 runs
Summary
./sapi/cli/php x.php ran
1.25 ± 0.03 times faster than ./sapi/cli/php_old x.php
```
On an i7-1185G7:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 67.9 ms ± 1.1 ms [User: 64.8 ms, System: 3.2 ms]
Range (min … max): 66.6 ms … 72.8 ms 43 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 84.8 ms ± 1.1 ms [User: 81.0 ms, System: 3.9 ms]
Range (min … max): 82.6 ms … 88.0 ms 34 runs
Summary
./sapi/cli/php x.php ran
1.25 ± 0.03 times faster than ./sapi/cli/php_old x.php
```
Because the properties table contains both a numeric index and a string
index that map to 0 in a symbol table, this causes an assertion failure.
Looking at the manual page of get_object_vars(), it seems that only real
properties must be included. Given that SplFixedArray's elements are not
accessible like properties, they should be excluded. This restores PHP
8.3 behaviour. The reason that this didn't cause problems on 8.3 is
because it used a different handler (get_properties).
Closes GH-17206.
* Include from build dir first
This fixes out of tree builds by ensuring that configure artifacts are included
from the build dir.
Before, out of tree builds would preferably include files from the src dir, as
the include path was defined as follows (ignoring includes from ext/ and sapi/) :
-I$(top_builddir)/main
-I$(top_srcdir)
-I$(top_builddir)/TSRM
-I$(top_builddir)/Zend
-I$(top_srcdir)/main
-I$(top_srcdir)/Zend
-I$(top_srcdir)/TSRM
-I$(top_builddir)/
As a result, an out of tree build would include configure artifacts such as
`main/php_config.h` from the src dir.
After this change, the include path is defined as follows:
-I$(top_builddir)/main
-I$(top_builddir)
-I$(top_srcdir)/main
-I$(top_srcdir)
-I$(top_builddir)/TSRM
-I$(top_builddir)/Zend
-I$(top_srcdir)/Zend
-I$(top_srcdir)/TSRM
* Fix extension include path for out of tree builds
* Include config.h with the brackets form
`#include "config.h"` searches in the directory containing the including-file
before any other include path. This can include the wrong config.h when building
out of tree and a config.h exists in the source tree.
Using `#include <config.h>` uses exclusively the include path, and gives
priority to the build dir.
When unserializing, the cached_resize field was not reset to -1
correctly, causing the setSize() method to think we were inside of a
resize operation.
Closes GH-13543.
Upon resizing, the elements are destroyed from lower index to higher
index. When an element refers to an object with a destructor, it can
refer to a lower (i.e. already destroyed) element, causing a uaf.
Set refcounted zvals to NULL after destroying them to avoid a uaf.
Closes GH-11959.
This merges all usages of emitting an offset TypeError into a new ZEND_API function
zend_illegal_container_offset(const zend_string* container, const zval *offset, int type);
Where the container should represent the type on which the access is attempted (e.g. string, array)
The offset zval that is used, where the error message will display its type
The type of access, which should be a BP_VAR_* constant, to get special message for isset/empty/unset
* PHP-8.2:
Fix GH-10907: Unable to serialize processed SplFixedArrays in PHP 8.2.4
Fix GH-8979: Possible Memory Leak with SSL-enabled MySQL connections
The properties table can also contain numeric entries after a rebuild of
the table based on the array. Since the array can only contain numeric
entries, and the properties table can contain a mix of both, we'll add
the numeric entries from the array and only the string entries from the
properties table. To implement this we simply check if the key from the
properties table is a string.
Closes GH-10921.
* Make handling of SplFixedArray properties more consistent
Create a brand new reference counted array every time in SplFixedArray
to be freed by the callers (or return null).
Switch from overriding `get_properties` to overriding `get_properties_for` handler
* Print objects with null hash table like others in print_r
Noticed when working on subsequent commits for SplFixedArray.
Make whether zend_get_properties_for returns null or an empty array
invisible to the end user - it would be always be a non-null array for
user-defined classes.
Always print newlines with `\n\s*(\n\s*)` after objects
Noticed when working on SplFixedArray changes, e.g. in
ext/spl/tests/SplFixedArray__construct_param_null.phpt
* Emit deprecation warnings when adding dynamic properties to classes during unserialization - this will become an Error in php 9.0.
(Adding dynamic properties in other contexts was already a deprecation warning - the use case of unserialization was overlooked)
* Throw an error when attempting to add a dynamic property to a `readonly` class when unserializing
* Add new serialization methods `__serialize`/`__unserialize` for SplFixedArray to avoid creating deprecated dynamic
properties that would then be added to the backing fixed-size array
* Don't add named dynamic/declared properties (e.g. $obj->foo) of SplFixedArray to the backing array when unserializing
* Update tests to declare properties or to expect the deprecation warning
* Add news entry
Co-authored-by: Tyson Andre <tysonandre775@hotmail.com>