php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #64555 foreach no longer copies keys if they seem to be interned
Submitted: 2013-03-31 11:21 UTC Modified: 2013-03-31 11:24 UTC
From: arpad@php.net Assigned: nikic
Status: Closed Package: Scripting Engine problem
PHP Version: 5.5.0beta1 OS:
Private report: No CVE-ID:
 [2013-03-31 11:21 UTC] arpad@php.net
Description:
------------
Foreach used to always copy string keys:
    key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL);

Since fcc6611de9054327441786e52444b5f8eecdd525 it instead uses:
    zend_hash_get_current_key_zval(fe_ht, key);

This only copies string keys if IS_INTERNED(), however in some cases (at least in get_object_vars() like in the test script) the key name is an unmangled property name which is *within* an interned string. So IS_INTERNED is true but INTERNED_LEN and INTERNED_HASH are nonsense.

The later unset and assignment in the test script use the nonsense INTERNED_HASH.

The simple fix is to make get_object_vars() copy the property names (as in the attached patch) but it's quite possible that other code has been broken in the same way, so the safer fix might be to force the copy again.


Test script:
---------------
https://gist.github.com/arraypad/5280321

Expected result:
----------------
Unsetting: unsetme
Changing: keepme
array(1) {
  ["keepme"]=>
  int(43)
}
array(1) {
  [0]=>
  string(6) "keepme"
}

Actual result:
--------------
Unsetting: unsetme
Changing: keepme
array(3) {
  ["unsetme"]=>
  int(1)
  ["keepme"]=>
  int(43)
  ["keepme"]=>
  int(42)
}
array(3) {
  [0]=>
  string(7) "unsetme"
  [1]=>
  string(6) "keepme"
  [2]=>
  string(6) "keepme"
}

Patches

foreach-copy-get_object_vars (last revision 2013-03-31 11:21 UTC) by arpad)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-03-31 11:24 UTC] arpad@php.net
-Assigned To: +Assigned To: nikic
 [2013-03-31 11:24 UTC] arpad@php.net
N.B. This indirectly causes a fatal error when using ZF1 forms so the impact is very high.
 [2013-04-03 18:33 UTC] nikic@php.net
Automatic comment on behalf of nikic
Revision: http://git.php.net/?p=php-src.git;a=commit;h=1f34ccbe34783f5671bc2a68e7299cea7493c82b
Log: Fix bug #64555: foreach no longer copies keys if they are interned
 [2013-04-03 18:33 UTC] nikic@php.net
-Status: Assigned +Status: Closed
 [2013-04-03 18:35 UTC] nikic@php.net
I went with always copying the key for now. Doing the copy in get_object_vars might be better, but would require a more thorough review of where else this could go wrong.
 [2013-11-17 09:31 UTC] laruence@php.net
Automatic comment on behalf of nikic
Revision: http://git.php.net/?p=php-src.git;a=commit;h=1f34ccbe34783f5671bc2a68e7299cea7493c82b
Log: Fix bug #64555: foreach no longer copies keys if they are interned
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Fri Apr 18 10:03:03 2014 UTC