ID: 48693 Comment by: peter at lvp-media dot com Reported By: peter at lvp-media dot com Status: Open Bug Type: Scripting Engine problem Operating System: n/a PHP Version: 5.3CVS-2009-06-25 (snap) New Comment:
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 (); ?> Previous Comments: ------------------------------------------------------------------------ [2009-06-25 13:46:51] 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: ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=48693&edit=1