php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73753 unserialized array pointer not advancing
Submitted: 2016-12-15 19:14 UTC Modified: 2016-12-16 14:47 UTC
From: devosc at gmail dot com Assigned:
Status: Closed Package: Scripting Engine problem
PHP Version: 7.1.0 OS:
Private report: No CVE-ID:
 [2016-12-15 19:14 UTC] devosc at gmail dot com
Description:
------------
Internal pointer of unserialized array does not advance correctly.

Test script:
---------------
<?php

function iterate($current, $queue, $result = null)
{
    if (!$current) {
        return $result;
    }

    return iterate(step($queue), $queue, $current);
}

function step(&$queue)
{
    return next($queue);
}

function start($queue)
{
    return current($queue);
}

function traverse($queue)
{
    return iterate(start($queue), $queue);
}

$queue = ['foo', 'bar', 'baz'];

$queue = unserialize(serialize($queue));

echo traverse($queue); //baz

Expected result:
----------------
It should output 'baz'.

Actual result:
--------------
Recursion error. The internal pointer is stuck on the second item and does not move forward. It works in 5.6 and when $queue is a reference in the signature of the iterate function. Seems inconsistent.

Patches

Add a Patch

Pull Requests

Pull requests:

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-12-16 14:47 UTC] cmb@php.net
-Status: Open +Status: Verified
 [2016-12-16 14:47 UTC] cmb@php.net
Confirmed: <https://3v4l.org/QmfJM#v563>.
 [2016-12-20 23:19 UTC] dave at mudsite dot com
It looks like this problem has to do with unpacked arrays.  You can change the $queue to:

$queue = [1 = 'foo', 'b' => 'bar', 'baz'];

without the serialize/unserialize and demonstrate the same problem.


I'm not overly versed with the packed/unpacked array but I believe this issue was introduced with b250f467035d3307853b6cf03be3b6b898bcaa80 (included in PHP 7.0).  The problem being with the zend_array_dup(), specifically how it handles the else case (non-packed array).  It attempts to zend_array_dup_elements(), which loops trying to dupe each element.  If it can, it keeps going.  Only when it can't, when due to inderect&undef, or when has holes&undef, would it fall into a case where it'd check if the idx equals the source arrays internal pointer.

I believe the fix to this would be to change the zend_array_dup_elements, to also check the source's internal index to the current idx, and if they match set the targets.  It does fix this bugs problem, but would want to ensure that it's valid for other cases I'm not overly familiar with.
 [2016-12-21 20:20 UTC] nikic@php.net
Automatic comment on behalf of dave@mudsite.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=5733fd1cafe8d0e2306626c525ad081b7ee30d96
Log: Fix #73753 - Unpacked Arrays and Duplication
 [2016-12-21 20:20 UTC] nikic@php.net
-Status: Verified +Status: Closed
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Wed Feb 22 20:01:42 2017 UTC