Bug #73816 [Opn]: Broken eval(anonymous class)
| From: | nicolas dot grekas+php at gmail dot com | Date: | Mon, 26 Dec 2016 21:51:23 +0000 |
| Subject: | Bug #73816 [Opn]: Broken eval(anonymous class) | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-206214@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=73816&edit=1
ID: 73816
User updated by: nicolas dot grekas+php at gmail dot com
Reported by: nicolas dot grekas+php at gmail dot com
Summary: Broken eval(anonymous class)
Status: Open
Type: Bug
Package: Scripting Engine problem
PHP Version: 7.1.0
Block user comment: N
Private report: N
New Comment:
100% agree with this analysis. This still means eval+anonymous classes is kinda broken. I don't
know if that would be a proper fix, but can't we use the hash of the evaluated string as part
of the generated name? Or at least some nonce?
Previous Comments:
------------------------------------------------------------------------
[2016-12-26 20:48:22] dave at mudsite dot com
I believe you're right in the sense the fix for the referenced bug prevents your example from
working, but had you stored the result of the first call to anon() and tried to use it, you'd
have hit the bug that was fixed; the reference of the class would have been the second eval'd
anon class, rather than the first. I'd leave it to others to say if the previous, or current,
behavior is appropriate.
If we took your example and ran it with a slight change, storing the return of anon() to variables
and var_dumping after you'd expose the bug that's resolved (kinda). You'd see that
both c1, and c2 do reference a class-entry, but it'd be the second updated pointer to the
entry.
https://3v4l.org/RiRcW
If you were to then set the prop1 before creating it again, you'd get even weirder output where
prop1 wouldn't exist.
https://3v4l.org/Eq3Di
I'd believe the current (7.0.10, 7.1.0) results ought to be correct. Where an anon class is
defined it should be the only entry in the class-table. Since the actual name of the class is
something along the lines of:
class@anonymous\0/Path/to/file.php(6) : eval()'d code0xdeadbeef
Where the only printed value of this name is up to that nul byte, however, the hash into the class
table you'd see references the memory location where the 'new class()' is defined.
Which, if your eval() line is at the same location the memory location never changes, even though
you change the properties in it.
------------------------------------------------------------------------
[2016-12-26 12:48:11] nicolas dot grekas+php at gmail dot com
Maybe introduced by the fix for https://bugs.php.net/72594
?
------------------------------------------------------------------------
[2016-12-26 12:34:40] nicolas dot grekas+php at gmail dot com
Description:
------------
Calling several times eval() to create different anonymous classes doesn't create new anonymous
classes but always returns the first one.
Used to work until 7.0.10 & 7.1.0 which both have the bug.
See https://3v4l.org/t7c5Z
Test script:
---------------
<?php
function anon()
{
static $i = 0;
return eval(sprintf('return new class { private $prop%s; };', ++$i));
}
var_dump(anon());
var_dump(anon());
Expected result:
----------------
object(class@anonymous)#1 (1) { ["prop1":"class@anonymous":private]=> NULL }
object(class@anonymous)#1 (1) { ["prop2":"class@anonymous":private]=> NULL }
Actual result:
--------------
object(class@anonymous)#1 (1) { ["prop1":"class@anonymous":private]=> NULL }
object(class@anonymous)#1 (1) { ["prop1":"class@anonymous":private]=> NULL }
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=73816&edit=1