php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #54860 PHP crash when using closures + extract(EXTR_REFS)
Submitted: 2011-05-19 12:03 UTC Modified: 2011-08-03 06:33 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: ninzya at inbox dot lv Assigned:
Status: Closed Package: Reproducible crash
PHP Version: 5.3.6 OS: Windows 7
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 you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: ninzya at inbox dot lv
New email:
PHP Version: OS:

 

 [2011-05-19 12:03 UTC] ninzya at inbox dot lv
Description:
------------
See test script.

PHP 5.3.5 is not affected.

Test script:
---------------
// Initially $Object is not a reference and contains a "pointer"
// to an stdClass object.
$Object =new stdClass; /**/ echo 'New: '; debug_zval_dump( $Object);

// $Object becomes a reference to the "pointer" to an stdClass.
$Object =&$Object; /**/ echo 'Self-reference: '; debug_zval_dump( $Object);

// Now we import $Object into closure by value. In theory,
// $Object, that is inside closure, should not be a reference, but rather
// should be a variable, that "points" to stdClass (i.e. an equivalent of
//  $ImportedObject in expression "$ImportedObject =$Object").
$closure =function() use( $Object) {
	// Once you manipulate $Object, you get PHP crashed.
	$Object->x =10;
	//debug_zval_dump( $Object);
};

// By calling extract() we make $Object to reference a new stdClass instance.
extract( array( 'Object' =>new stdClass), EXTR_REFS);

echo 'After extract: '; debug_zval_dump( $Object);

// now we execute closure and get PHP crashed
$closure();

Expected result:
----------------
PHP should not crash.

Actual result:
--------------
PHP crashes.

If you put die() right before $closure(), then you get following output:

line 1: New: object(stdClass)#1 (0) refcount(2){
line 2: }
line 3: Self-reference: object(stdClass)#1 (0) refcount(1){
line 4: }
line 5: After extract: object(stdClass)#3 (0) refcount(2){
line 6: }

Some questions regarding that output:
1) why there is refcount(2) in the first line? Isn't the object referenced only 
once and by $Object variable? I would expect to see refcount(1) here. As you can 
see on line 3, refcount seems to become correct after self-referencing is being 
made.
2) why line 5 says object(stdClass)#3, while there were only two (and not 3) 
stdClass objects allocated? If you comment out closure's definition, then you 
get object(stdClass)#2 (an expected output). Does closure clone $Object when you 
say "use($Object)"? Shouldn't the stdClass object be simply "referenced" by the 
"use($Object)"?

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-05-19 14:02 UTC] ninzya at inbox dot lv
Sorry, extract() has nothing to do with this issue.
I was able to come up with more compact test script with no use of extract():

$x =new stdClass;
$y =&$x;

for( $i =0; $i < 2; ++$i) {
	$closure =function() use( $y) {
		$y->someProperty ='someValue';// crashes on second iteration
	};
	$closure();
}

This code does not crash PHP 5.3.5. It seems that references + closures became 
broken in 5.3.6.
 [2011-05-21 20:07 UTC] felipe@php.net
-Status: Open +Status: Feedback
 [2011-05-21 20:07 UTC] felipe@php.net
Please try using this snapshot:

  http://snaps.php.net/php5.3-latest.tar.gz
 
For Windows:

  http://windows.php.net/snapshots/

I can't reproduce it.
 [2011-05-23 09:20 UTC] ninzya at inbox dot lv
Works fine with 5.3 r311342.
 [2011-08-03 06:33 UTC] ninzya at inbox dot lv
-Status: Feedback +Status: Closed
 [2011-08-03 06:33 UTC] ninzya at inbox dot lv
Fixed in 5.3.7.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Thu Jul 03 16:01:36 2025 UTC