php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #60498 Unset obj.prop. thru ArrayAccess while iterating thru ArrayIterator cause error
Submitted: 2011-12-12 12:28 UTC Modified: 2021-01-26 11:22 UTC
Votes:9
Avg. Score:4.6 ± 0.8
Reproduced:8 of 8 (100.0%)
Same Version:7 (87.5%)
Same OS:6 (75.0%)
From: michal dot brzuchalski at gmail dot com Assigned: nikic (profile)
Status: Closed Package: SPL related
PHP Version: 5.6 OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: michal dot brzuchalski at gmail dot com
New email:
PHP Version: OS:

 

 [2011-12-12 12:28 UTC] michal dot brzuchalski at gmail dot com
Description:
------------
Using foreach to iterate object which implements IteratorAggregate and 
ArrayAccess while iterating with iterator created by ArrayIterator($this) causes 
error in internal spl_array_update_pos when trying to unset object property thru 
arrayaccess interface:

debug:

#0  0x0000000802f9cd2f in spl_array_update_pos (intern=0x80847d778) at 
/usr/ports/lang/php5/work/php-5.3.8/ext/spl/spl_array.c:101
101                     intern->pos_h = pos->h;
[New Thread 8016041c0 (LWP 100187/httpd)]
(gdb) bt
#0  0x0000000802f9cd2f in spl_array_update_pos (intern=0x80847d778) at 
/usr/ports/lang/php5/work/php-5.3.8/ext/spl/spl_array.c:101
#1  0x0000000802fa00aa in spl_array_next_no_verify (intern=0x80847d778, 
aht=0x8082764a8) at /usr/ports/lang/php5/work/php-5.3.8/ext/spl/spl_array.c:858
#2  0x0000000802fa0566 in spl_array_it_move_forward (iter=0x808428330) at 
/usr/ports/lang/php5/work/php-5.3.8/ext/spl/spl_array.c:983
#3  0x0000000803189a25 in ZEND_FE_FETCH_SPEC_VAR_HANDLER 
(execute_data=0x807a0a268) at zend_vm_execute.h:9014
#4  0x00000008031616aa in execute (op_array=0x803af3d00) at 
zend_vm_execute.h:107
#5  0x000000080311c307 in zend_call_function (fci=0x7fffffffcc50, 
fci_cache=0x7fffffffcc20) at /usr/ports/lang/php5/work/php-
5.3.8/Zend/zend_execute_API.c:968
#6  0x0000000802fcd3ee in zif_call_user_func (ht=2, return_value=0x8082bd5d0, 
return_value_ptr=0x0, this_ptr=0x0, return_value_used=1) at 
/usr/ports/lang/php5/work/php-5.3.8/ext/standard/basic_functions.c:4772
#7  0x000000080316271c in zend_do_fcall_common_helper_SPEC 
(execute_data=0x807a09c48) at zend_vm_execute.h:320
#8  0x00000008031636c5 in ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER 
(execute_data=0x807a09c48) at zend_vm_execute.h:425
#9  0x00000008031616aa in execute (op_array=0x807af1c50) at 
zend_vm_execute.h:107
#10 0x000000080312de5d in zend_execute_scripts (type=8, retval=0x0, 
file_count=3) at /usr/ports/lang/php5/work/php-5.3.8/Zend/zend.c:1236
#11 0x00000008030ad482 in php_execute_script (primary_file=0x7fffffffe5a0) at 
/usr/ports/lang/php5/work/php-5.3.8/main/main.c:2284
#12 0x0000000803221e45 in php_handler (r=0x803ba40a0) at 
/usr/ports/lang/php5/work/php-5.3.8/sapi/apache2handler/sapi_apache2.c:669
#13 0x000000000043dd1a in ap_run_handler (r=0x803ba40a0) at config.c:157
#14 0x000000000043e643 in ap_invoke_handler (r=0x803ba40a0) at config.c:376
#15 0x000000000044f9d4 in ap_process_request (r=0x803ba40a0) at 
http_request.c:282
#16 0x000000000044c7b4 in ap_process_http_connection (c=0x803afa290) at 
http_core.c:190
#17 0x00000000004475aa in ap_run_process_connection (c=0x803afa290) at 
connection.c:43
#18 0x0000000000447a2b in ap_process_connection (c=0x803afa290, csd=0x803afa0a0) 
at connection.c:190
#19 0x0000000000456d85 in child_main (child_num_arg=37) at prefork.c:667
#20 0x0000000000456f3c in make_child (s=0x80161c708, slot=37) at prefork.c:768
#21 0x0000000000457629 in ap_mpm_run (_pconf=0x801615028, plog=0x801647028, 
s=0x80161c708) at prefork.c:1068
#22 0x000000000042410b in main (argc=2, argv=0x7fffffffeb20) at main.c:739
(gdb) bt full


Test script:
---------------
class obj implements \ArrayAccess , \IteratorAggregate {

    public function __construct() {
        foreach(array("one" => 1, "two" => 2, "three" => 3) as $offset => $value) $this->{$offset} = $value;
    }
    public function offsetSet($offset, $value) {
        $this->{$offset} = $value;
    }
    public function offsetExists($offset) {
        return isset($this->{$offset});
    }
    public function offsetUnset($offset) {
        unset($this->{$offset});
    }
    public function offsetGet($offset) {
        return isset($this->{$offset}) ? $this->{$offset} : null;
    }
	function getIterator() {
	  	return new \ArrayIterator($this);
	}
}

$obj = new obj;

foreach($obj as $offset => $value) unset($obj[$offset]);

print_r($obj);

foreach(get_object_vars($obj) as $offset => $value) unset($obj[$offset]);

print_r($obj);


Expected result:
----------------
obj Object
(
)
obj Object
(
)

Actual result:
--------------
The first foreach cause an internal error second one is ok

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-12-12 13:04 UTC] michal dot brzuchalski at gmail dot com
-Operating System: Unix +Operating System: FreeBSD
 [2011-12-12 13:04 UTC] michal dot brzuchalski at gmail dot com
Sorry no Unix but FreeBSD
 [2016-03-20 12:59 UTC] nikic@php.net
-Status: Open +Status: Verified -Operating System: FreeBSD +Operating System: -PHP Version: 5.3.8 +PHP Version: 5.6
 [2016-03-20 12:59 UTC] nikic@php.net
This issue still exists in PHP 5.6. It does not exist in PHP 7.0.

Valgrind:

==9299== Invalid read of size 8
==9299==    at 0x8FC1A6: zend_hash_move_forward_ex (zend_hash.c:1047)
==9299==    by 0x700BFC: spl_array_next_no_verify (spl_array.c:965)
==9299==    by 0x701009: spl_array_it_move_forward (spl_array.c:1079)
==9299==    by 0x94CB3A: ZEND_FE_FETCH_SPEC_VAR_HANDLER (zend_vm_execute.h:14027)
==9299==    by 0x92D8F5: execute_ex (zend_vm_execute.h:363)
==9299==    by 0x92D97E: zend_execute (zend_vm_execute.h:388)
==9299==    by 0x8E8CF3: zend_execute_scripts (zend.c:1341)
==9299==    by 0x84EED3: php_execute_script (main.c:2613)
==9299==    by 0x99D0C4: do_cli (php_cli.c:994)
==9299==    by 0x99E3F2: main (php_cli.c:1378)
==9299==  Address 0xbf77840 is 32 bytes inside a block of size 72 free'd
==9299==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9299==    by 0x8AEECA: _efree (zend_alloc.c:2437)
==9299==    by 0x8F9417: i_zend_hash_bucket_delete (zend_hash.c:187)
==9299==    by 0x8FAD3B: zend_hash_del_key_or_index (zend_hash.c:526)
==9299==    by 0x922CFB: zend_std_unset_property (zend_object_handlers.c:855)
==9299==    by 0x97CF42: ZEND_UNSET_OBJ_SPEC_UNUSED_CV_HANDLER (zend_vm_execute.h:30346)
==9299==    by 0x92D8F5: execute_ex (zend_vm_execute.h:363)
==9299==    by 0x92D97E: zend_execute (zend_vm_execute.h:388)
==9299==    by 0x8D35A8: zend_call_function (zend_execute_API.c:829)
==9299==    by 0x909088: zend_call_method (zend_interfaces.c:97)
==9299==    by 0x923098: zend_std_unset_dimension (zend_object_handlers.c:897)
==9299==    by 0x99A355: ZEND_UNSET_DIM_SPEC_CV_CV_HANDLER (zend_vm_execute.h:41212)
==9299==
 [2021-01-26 11:22 UTC] nikic@php.net
-Status: Verified +Status: Closed -Assigned To: +Assigned To: nikic
 [2021-01-26 11:22 UTC] nikic@php.net
Per above comment, the crash was fixed in PHP 7.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Tue Jul 01 02:01:36 2025 UTC