php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #33286 nested array_walk function broken
Submitted: 2005-06-09 19:35 UTC Modified: 2005-06-17 00:54 UTC
From: pumuckel at metropolis dot de Assigned: andrei (profile)
Status: Closed Package: Arrays related
PHP Version: 5CVS-2005-06-13 OS: Linux
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: pumuckel at metropolis dot de
New email:
PHP Version: OS:

 

 [2005-06-09 19:35 UTC] pumuckel at metropolis dot de
Description:
------------
Nested array_walk calls don't work.

Reason: BG(array_walk_fci_cache) will not get re-initialized after inner array_walk call.

Following patch will help - better solution would be a local array_walk_fci_cache var inside the php_walk_array function:

diff -u php-5.0.4/ext/standard/array.c php-5.0.4.patched/ext/standard/array.c 
--- php-5.0.4/ext/standard/array.c      2005-03-12 11:12:49.000000000 +0100
+++ php-5.0.4.patched/ext/standard/array.c      2005-06-09 19:31:43.000000000 +0200
@@ -1079,6 +1079,8 @@
                }
                zend_hash_move_forward_ex(target_hash, &pos);
        }
+
+    BG(array_walk_fci_cache) = empty_fcall_info_cache;
 
        return 0;
 }


Reproduce code:
---------------
<?php

function test_subfunc(&$item1, $key, &$prefix)
{
   echo "&nbsp;&nbsp;test_subfunc<br/>";
}

function test_func($item2, $key)
{
   echo "test_func<br/>";

   $arr = array(1, 2, 3, 4);
   array_walk($arr, 'test_subfunc', 'extra_arg');
}

$x = array(5,6,7);
array_walk($x, 'test_func');

?>


Expected result:
----------------
test_func
  test_subfunc
  test_subfunc
  test_subfunc
  test_subfunc
test_func
  test_subfunc
  test_subfunc
  test_subfunc
  test_subfunc
test_func
  test_subfunc
  test_subfunc
  test_subfunc
  test_subfunc

Actual result:
--------------
test_func
  test_subfunc
  test_subfunc
  test_subfunc
  test_subfunc

Warning: Missing argument 3 for test_subfunc() in foo.php on line 3
  test_subfunc
  test_subfunc

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-06-10 09:35 UTC] pumuckel at metropolis dot de
Here is the patch for using a local cache var instead of a global.

In nested loops using the global cache var only the innermost array_walk function can effectively make use of the cache. All outermost loops can't because cache always got cleared from innermost and therefor functions have to be relocated.

With local cache var this is not needed and we will get better performance with big nested arrays.

Patch:
diff -urw php-5.0.4/ext/standard/array.c php-5.0.4.patched/ext/standard/array.c
--- php-5.0.4/ext/standard/array.c      2005-03-12 11:12:49.000000000 +0100
+++ php-5.0.4.patched/ext/standard/array.c      2005-06-10 09:25:15.000000000 +0200
@@ -1008,6 +1008,7 @@
        uint   string_key_len;
        ulong  num_key;
        HashPosition pos;
+    zend_fcall_info_cache array_walk_fci_cache = empty_fcall_info_cache;

        /* Set up known arguments */
        args[1] = &key;
@@ -1051,7 +1052,7 @@
                        fci.no_separation = 0;

                        /* Call the userland function */
-                       if (zend_call_function(&fci, &BG(array_walk_fci_cache) TSRMLS_CC) == SUCCESS) {
+                       if (zend_call_function(&fci, &array_walk_fci_cache TSRMLS_CC) == SUCCESS) {
                                if (retval_ptr) {
                                        zval_ptr_dtor(&retval_ptr);
                                }
@@ -1094,7 +1095,6 @@
        HashTable *target_hash;

        argc = ZEND_NUM_ARGS();
-       BG(array_walk_fci_cache) = empty_fcall_info_cache;
        old_walk_func_name = BG(array_walk_func_name);
        if (argc < 2 || argc > 3 ||
                zend_get_parameters_ex(argc, &array, &BG(array_walk_func_name), &userdata) == FAILURE) {
@@ -1131,7 +1131,6 @@

        argc = ZEND_NUM_ARGS();
        old_walk_func_name = BG(array_walk_func_name);
-       BG(array_walk_fci_cache) = empty_fcall_info_cache;

        if (argc < 2 || argc > 3 ||
                zend_get_parameters_ex(argc, &array, &BG(array_walk_func_name), &userdata) == FAILURE) {
diff -urw php-5.0.4/ext/standard/basic_functions.h php-5.0.4.patched/ext/standard/basic_functions.h
--- php-5.0.4/ext/standard/basic_functions.h    2004-03-27 01:50:39.000000000 +0100
+++ php-5.0.4.patched/ext/standard/basic_functions.h    2005-06-10 09:24:46.000000000 +0200
@@ -154,7 +154,6 @@
        ulong strtok_len;
        char str_ebuf[40];
        zval **array_walk_func_name;
-       zend_fcall_info_cache array_walk_fci_cache;
        zval **user_compare_func_name;
        zend_fcall_info_cache user_compare_fci_cache;
        zend_llist *user_tick_functions;
 [2005-06-10 18:22 UTC] andrei@php.net
Can you provide a patch against HEAD? It seems that there are more uses of BG() global that your patch doesn't cover.
 [2005-06-13 09:37 UTC] pumuckel at metropolis dot de
Feedback (a bigger patch) was sent to Andrei Zmievski. I required I can post it here uuencoded.
 [2005-06-17 00:54 UTC] sniper@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Nov 23 07:01:29 2024 UTC