php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #75433 Possible array indicies regression in array_values
Submitted: 2017-10-24 20:43 UTC Modified: 2019-08-03 17:24 UTC
Votes:5
Avg. Score:4.2 ± 1.0
Reproduced:3 of 3 (100.0%)
Same Version:1 (33.3%)
Same OS:2 (66.7%)
From: bourigaultfabien at gmail dot com Assigned: pollita (profile)
Status: Closed Package: Arrays related
PHP Version: 7.2.0RC4 OS: Linux
Private report: No CVE-ID: None
 [2017-10-24 20:43 UTC] bourigaultfabien at gmail dot com
Description:
------------
It looks like there are some weird behavior with array indices. If you look at https://3v4l.org/IOvBR the output is is different for PHP 7.2+ (and also for HHVM 3.21+). After looking deeper at what may be wrong I ended to write https://3v4l.org/gG7BG which gives the same output for any PHP version. It looks like calling unset() on one array element and then appending an item to this array produce a different result in PHP 7.2+.


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-10-25 02:42 UTC] requinix@php.net
-Summary: Possible array indicies regression +Summary: Possible array indicies regression in array_values -Status: Open +Status: Analyzed -Package: *General Issues +Package: Arrays related
 [2017-10-25 02:42 UTC] requinix@php.net
> It looks like calling unset() on one array element and then appending an item to this array produce a different
> result in PHP 7.2+.
Close. PHP won't reuse the removed key in any version, even if it was at the end of the array.
The problem here is in array_values: https://3v4l.org/vlTD7

> $old = ['one', 'two', 'three', 'four'];
> unset($old[3]);
Before and after, $old is a particular form of array where it has consecutive integer keys starting from 0 in ascending order ("packed without holes"). In other words,
  array_keys($old) === range(0, count($old) - 1)

https://github.com/php/php-src/blob/php-7.2.0RC4/ext/standard/array.c#L4016
In PHP 7.2 array_values() gained an optimization: for packed no-hole arrays it returns the array as-is because the reindexing would not have changed anything, however it would have reset the value for the next array key by virtue of creating a new array. So it looks like there should be a check added for that as well. (Or maybe it gets bundled into HT_IS_WITHOUT_HOLES?)
 [2017-10-27 16:52 UTC] pollita@php.net
-Assigned To: +Assigned To: pollita
 [2017-10-27 17:09 UTC] pollita@php.net
https://github.com/php/php-src/commit/cc96166f743011c037d9915681b28c363c189e0a should address this (thanks for the catch during pre-release!)

Going to keep this open for a bit as array_slice() is impacted by a similar root cause (in 7.3 only) and this is as good a place to track it as any.
 [2017-12-05 22:47 UTC] domen at jollydeck dot com
It looks like this regression still affects array_values on empty arrays (arrays which previously had values but values are all unseted before using array_values):
https://3v4l.org/U4qRd
 [2017-12-11 10:46 UTC] geompse at gmail dot com
As domen at jollydeck dot com pointed out, the issue is not solved for empty arrays. My test case is so close to his it seems copy-and-paste'd : https://3v4l.org/5rncA
 [2019-08-03 17:24 UTC] cmb@php.net
-Status: Analyzed +Status: Closed
 [2019-08-03 17:24 UTC] cmb@php.net
Issue is fixed as of PHP 7.2.2.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Dec 23 03:01:27 2024 UTC