DDC-2785: spl_object_hash_collisions #3481

Closed
opened 2026-01-22 14:20:43 +01:00 by admin · 6 comments
Owner

Originally created by @doctrinebot on GitHub (Nov 8, 2013).

Originally assigned to: @Majkl578 on GitHub.

Jira issue originally created by user flack:

After reading DDC-1896 and DDC-136, I'm not exactly sure if this qualifies as a bug, but anyways, here's my code to reproduce:

    public function test*hash*collision()
    {
        $counter = 0;
        do
        {
            $object = $this->create_object();
            $counter<ins></ins>;
            if ($counter > 1000)
            {
                //mark as skipped ? (I never hit this on PHP 5.3 at least)
                break;
            }
        }
        while ($object === false);

        // This fails with "Failed asserting that 1 matches expected 2."
        $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE*NEW, $this->*em->getUnitOfWork()->getEntityState($object));
    }

    private function create_object()
    {
        static $hashes = array();
        $phone = new CmsPhonenumber();
        $phone->phonenumber = "1234";
        $hash = spl*object*hash($phone);
        $this->_em->persist($phone);

        if (!array*key*exists($hash, $hashes))
        {
            $hashes[$hash] = true;
            $this->_em->flush($phone);
            $this->_em->remove($phone);
            $this->_em->flush($phone);
            return false;
        }
        // Bingo! We have a new object with a recycled hash
        return $phone;
    }
Originally created by @doctrinebot on GitHub (Nov 8, 2013). Originally assigned to: @Majkl578 on GitHub. Jira issue originally created by user flack: After reading [DDC-1896](http://www.doctrine-project.org/jira/browse/DDC-1896) and [DDC-136](http://www.doctrine-project.org/jira/browse/DDC-136), I'm not exactly sure if this qualifies as a bug, but anyways, here's my code to reproduce: ``` public function test*hash*collision() { $counter = 0; do { $object = $this->create_object(); $counter<ins></ins>; if ($counter > 1000) { //mark as skipped ? (I never hit this on PHP 5.3 at least) break; } } while ($object === false); // This fails with "Failed asserting that 1 matches expected 2." $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE*NEW, $this->*em->getUnitOfWork()->getEntityState($object)); } private function create_object() { static $hashes = array(); $phone = new CmsPhonenumber(); $phone->phonenumber = "1234"; $hash = spl*object*hash($phone); $this->_em->persist($phone); if (!array*key*exists($hash, $hashes)) { $hashes[$hash] = true; $this->_em->flush($phone); $this->_em->remove($phone); $this->_em->flush($phone); return false; } // Bingo! We have a new object with a recycled hash return $phone; } ```
admin added the BugWon't Fix labels 2026-01-22 14:20:43 +01:00
admin closed this issue 2026-01-22 14:20:43 +01:00
Author
Owner

@doctrinebot commented on GitHub (Nov 8, 2013):

Comment created by @ocramius:

Are you able to reproduce the test also without statics?

@doctrinebot commented on GitHub (Nov 8, 2013): Comment created by @ocramius: Are you able to reproduce the test also without statics?
Author
Owner

@doctrinebot commented on GitHub (Nov 8, 2013):

Comment created by flack:

Yes, if I switch to $this->hashes (private $hashes = array()), the result is the same

@doctrinebot commented on GitHub (Nov 8, 2013): Comment created by flack: Yes, if I switch to $this->hashes (private $hashes = array()), the result is the same
Author
Owner

@doctrinebot commented on GitHub (Nov 8, 2013):

Comment created by flack:

Here's the complete test without statics & according to Doctrine CS (AFAICT):

<?php

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\Tests\Models\CMS\CmsPhonenumber;

require*once __DIR_* . '/../../../TestInit.php';

/****
 * @group [DDC-2785](http://www.doctrine-project.org/jira/browse/DDC-2785)
 */
class DDC2785Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
    public function setUp()
    {
        $this->useModelSet('cms');
        parent::setUp();
    }

    private $hashes = array();

    public function testIssue()
    {
        $counter = 0;
        do
        {
            $object = $this->createObject();
            $counter<ins></ins>;
            if ($counter > 1000)
            {
                //mark as skipped ? (I never hit this on PHP 5.3 at least)
                break;
            }
        }
        while ($object === false);

        $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE*NEW, $this->*em->getUnitOfWork()->getEntityState($object));
    }

    private function createObject()
    {
        $phone = new CmsPhonenumber();
        $phone->phonenumber = "1234";
        $hash = spl*object*hash($phone);
        $this->_em->persist($phone);

        if (!array*key*exists($hash, $this->hashes))
        {
            $this->hashes[$hash] = true;
            $this->_em->flush();
            $this->_em->remove($phone);
            $this->_em->flush();
            return false;
        }

        return $phone;
    }
}

I can try and send this as a pull request, if it helps

@doctrinebot commented on GitHub (Nov 8, 2013): Comment created by flack: Here's the complete test without statics & according to Doctrine CS (AFAICT): ``` <?php namespace Doctrine\Tests\ORM\Functional\Ticket; use Doctrine\Tests\Models\CMS\CmsPhonenumber; require*once __DIR_* . '/../../../TestInit.php'; /**** * @group [DDC-2785](http://www.doctrine-project.org/jira/browse/DDC-2785) */ class DDC2785Test extends \Doctrine\Tests\OrmFunctionalTestCase { public function setUp() { $this->useModelSet('cms'); parent::setUp(); } private $hashes = array(); public function testIssue() { $counter = 0; do { $object = $this->createObject(); $counter<ins></ins>; if ($counter > 1000) { //mark as skipped ? (I never hit this on PHP 5.3 at least) break; } } while ($object === false); $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE*NEW, $this->*em->getUnitOfWork()->getEntityState($object)); } private function createObject() { $phone = new CmsPhonenumber(); $phone->phonenumber = "1234"; $hash = spl*object*hash($phone); $this->_em->persist($phone); if (!array*key*exists($hash, $this->hashes)) { $this->hashes[$hash] = true; $this->_em->flush(); $this->_em->remove($phone); $this->_em->flush(); return false; } return $phone; } } ``` I can try and send this as a pull request, if it helps
Author
Owner

@doctrinebot commented on GitHub (Jan 24, 2015):

Comment created by @doctrinebot:

A related Github Pull-Request [GH-843] was labeled:
https://github.com/doctrine/doctrine2/pull/843

@doctrinebot commented on GitHub (Jan 24, 2015): Comment created by @doctrinebot: A related Github Pull-Request [GH-843] was labeled: https://github.com/doctrine/doctrine2/pull/843
Author
Owner

@Majkl578 commented on GitHub (Dec 19, 2017):

Duplicate of #3037.

@Majkl578 commented on GitHub (Dec 19, 2017): Duplicate of #3037.
Author
Owner

@mpdude commented on GitHub (Jun 22, 2023):

The OP created #843 with a slight variation of the above test code

@mpdude commented on GitHub (Jun 22, 2023): The OP created #843 with a slight variation of the above test code
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#3481