php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #69291 SPL directory tests fail under some conditions
Submitted: 2015-03-24 19:25 UTC Modified: 2020-04-24 20:31 UTC
From: danack@php.net Assigned:
Status: Open Package: SPL related
PHP Version: 5.5.23 OS: Centos
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 this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: danack@php.net
New email:
PHP Version: OS:

 

 [2015-03-24 19:25 UTC] danack@php.net
Description:
------------
The tests ext/spl/tests/dit_004.phpt and ext/spl/tests/dit_005.phpt fail on Centos running in a VirtualBox VM, but only under certain conditions:

* when they are run through "php run-tests.php ext/spl/tests/dit_004.phpt" - both of them fail.

* dit_004 fails when run as "valgrind -q --tool=memcheck /usr/bin/php ext/spl/tests/dit_004.php". dit_005.phpt doesn't fail and works fine.

Both of the tests run as expected when you just run the underlying PHP code that they are calling.

The behaviour is as if the cloned object is jumping to a random entry in the DirectoryIterator

Test script:
---------------
<?php
$a = new DirectoryIterator(__DIR__);
$b = clone $a;

$bValue = (string)$b;
$aValue = (string)$a;
if ($aValue != $bValue) {
	echo "aValue and bValue should be the same".PHP_EOL;
	echo $aValue.PHP_EOL;
	echo $bValue.PHP_EOL;
}
else {
    echo "Ok";
}


Expected result:
----------------
Ok

Actual result:
--------------
aValue and bValue should be the same
.
SplObjectStorage_offsetGet_invalid_parameter.phpt

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-03-24 19:25 UTC] danack@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: danack
 [2015-03-27 18:23 UTC] danack@php.net
Whoop - I added the PR to the wrong issue. The PR is for something else entirely, but apparently there is no way to delete it.
 [2015-04-02 14:47 UTC] danack@php.net
Okay - I understand what is happening, but can't tell what the 'correct' behaviour should be.

The code is assuming that DirectoryIterator will return objects alphabetically. It isn't doing so. Instead the file entries are listed alphabetically within 'blocks', but the blocks are ordered in reverse.

i.e. the first entry in the cloned iterator is SplObjectStorage_getHash.phpt, while the first entry in the original iterator is array_001.phpt


The full output is https://gist.github.com/Danack/e9c7ca12958cdd180197.


TL:DR the test assumes that DirectoryIterator always returns values in the same alphabetical order, it doesn't. And so the test fails sometimes.
 [2015-04-03 19:45 UTC] tyrael@php.net
I've deleted the link to the wrong PR.
 [2017-01-22 16:36 UTC] danack@php.net
-Assigned To: danack +Assigned To:
 [2020-04-24 18:54 UTC] alexinbeijing at gmail dot com
Can't reproduce the failure described here. Both of the tests run fine whether run through `php run-tests.php` or not, and whether run under valgrind or not.

5 years have passed, a lot has changed, and whatever was causing this bug has probably been fixed. The ticket should be closed.
 [2020-04-24 20:31 UTC] danack@php.net
Hi Alex,

I'm pretty sure the bad assumption is still there: https://github.com/php/php-src/blob/826a7456717b8fab22d43deedf7b6ab1b1f426be/ext/spl/spl_directory.c#L371

Below is an example of how cloning a directoryIterator doesn't result in an object that is actually a clone


<?php

$a = new DirectoryIterator(__DIR__);

$baseName = basename(__FILE__);
$found = false;

while($found == false) {
    $a->next();
    if ($baseName === (string)$a) {
        $found = true;
    }
};

file_put_contents('created_file.txt', 'feel free to delete');


$b = clone $a;
// Cloning should result in same object, right?

if ((string)$b != (string)$a) {
    // surprise!
    // output is "file 1: dir_bug.php file 2: created_file.txt"
    printf(
        "file 1: %s file 2: %s",
        (string)$a,
        (string)$b
    );
}

unlink('created_file.txt');
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Wed Oct 28 04:01:23 2020 UTC