php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #48693 Double declaration of __lambda_func when lambda wrongly formatted
Submitted: 2009-06-25 13:46 UTC Modified: 2009-06-30 11:46 UTC
From: peter at lvp-media dot com Assigned: felipe (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 5.3CVS-2009-06-25 (snap) OS: n/a
Private report: No CVE-ID: None
View Add Comment Developer Edit
Anyone can comment on a bug. Have a simpler test case? Does it work for you on a different platform? Let us know!
Just going to say 'Me too!'? Don't clutter the database with that please !
Your email address:
MUST BE VALID
Solve the problem:
4 + 34 = ?
Subscribe to this entry?

 
 [2009-06-25 13:46 UTC] peter at lvp-media dot com
Description:
------------
When creating a new lambda function using create_function, any code behind an extra right curly brace (which closes the function) gets executed. This is known and expected behaviour of eval, so no problem so far. However, when the function itself does not contain parsing errors, while the code after it does, the function gets created (and becomes available) while zend_eval_stringl() returns false. Therefore the function's name, defaulting to LAMBDA_TEMP_FUNCNAME, will not be changed and any future calls to create_functions will fail using a fatal error ("Cannot redeclare __lambda_func()"). Reproduce code is included.

The echo should output "1", however, the fatal error gets thrown instead. While this absolutely isn't a problem that (should) occur very often, fixing it seemed fairly easy so I created two patches.

The first patch checks whether any function named LAMBDA_TEMP_FUNCNAME exists if zend_eval_stringl() fails, and if it does, renames it to lambda_%d as would be done if the eval succeeded. After all, the function itself was fine, so the function name can be returned as well. zend_eval_stringl() outputs the parse error automatically so the script-owner gets informed of the problem as well. The second patch is easier, it simply removes any function called LAMBDA_TEMP_FUNCNAME if it exists.

PATCH 1:

--- zend_builtin_functions.c    2009-06-25 15:23:45.000000000 +0200
+++ zend_builtin_functions_new.c        2009-06-25 15:40:34.000000000 +0200
@@ -1737,8 +1737,8 @@ ZEND_FUNCTION(create_function)
        efree(eval_name);

-       if (retval==SUCCESS) {
+       if (retval==SUCCESS || zend_hash_find(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), (void **) &func)!=FAILURE) {
                zend_function new_function, *func;

-               if (zend_hash_find(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), (void **) &func)==FAILURE) {
+               if (retval==SUCCESS && zend_hash_find(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), (void **) &func)==FAILURE) {
                        zend_error(E_ERROR, "Unexpected inconsistency in create_function()");
                        RETURN_FALSE;

PATCH 2:

--- zend_builtin_functions.c            2009-06-25 15:23:45.000000000 +0200
+++ zend_builtin_functions_new.c        2009-06-25 15:23:45.000000000 +0200
@@ -1756,4 +1756,7 @@ ZEND_FUNCTION(create_function)
                RETURN_STRINGL(function_name, function_name_length, 0);
        } else {
+                if (zend_hash_find(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), (void **) &func)!=FAILURE) {
+                       zend_hash_del(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME));
+               }
                RETURN_FALSE;
        }

Reproduce code:
---------------
<?php
$borked = create_function ('', 'return 1; } else {}'); // unexpected else {}
$foo    = create_function ('', 'return 1;');

echo $foo ();
?>

Expected result:
----------------
1

Actual result:
--------------
Fatal error: Cannot redeclare __lambda_func() (previously declared in /home/peter/test.php(2) : runtime-created function:

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-06-25 13:52 UTC] peter at lvp-media dot com
The reproduce code got cut off, the else{} should be in the comment right behind the $borked-assignment.

<?php
$borked = create_function ('', 'return 1; } else {}'); // parse error
$foo    = create_function ('', 'return 1;');

echo $foo ();
?>
 [2009-06-28 01:22 UTC] felipe@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

I've committed the patch 2 (slightly modified) in 5.2 and HEAD.
5.3 in soon.

Thanks.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 16 18:01:30 2024 UTC