From: moo dot tinys at gmail dot com Operating system: PHP version: 5.3CVS-2008-12-12 (CVS) PHP Bug Type: Scripting Engine problem Bug description: compile time depends on runtime constants ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION
Description: ------------ let's focus our eyes on ==== zend_compile.c function zend_do_receive_arg void zend_do_receive_arg(zend_uchar op, const znode *var, const znode *offset, const znode *initialization, znode *class_type, const znode *varname, zend_uchar pass_by_reference TSRMLS_DC) { ........... if (op == ZEND_RECV_INIT) { if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { cur_arg_info->allow_null = 1; } else { zend_error(E_COMPILE_ERROR, "Default value for parameters with a class type hint can only be NULL"); } } ====================== (the following gdb input/output is still using macro for your reading, expand the macro if you want to execute) test case 1 precondition: CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION; before zend_compile_file break at function zend_do_receive_arg and (gdb) print Z_TYPE(initialization->u.constant) == IS_NULL 1 (true) which means php still subst "null" to "IS_NULL" test case 2 precondtion: let's assume ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION is working for zend_do_receive_arg, simply empty hash table: EG(zend_constants) = &an_empty_hash_table; before zend_compile_file break at function zend_do_receive_arg and (gdb) print Z_TYPE(initialization->u.constant) == IS_NULL 0 (false) (gdb) print Z_TYPE(initialization->u.constant) == IS_CONSTANT 0 (false) so what is that? (gdb) print Z_TYPE(initialization->u.constant) 24 (gdb) print (Z_TYPE(initialization->u.constant) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT 1 (true) ************ ok, we get the first bug (gdb) p !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL")) 0 (false) why? (gdb) p Z_STRVAL(initialization->u.constant) "My\\NS\\null" this is the reason. looks likestrcasecmp is not enough here at compile time. or you could just handle abc(array $a = null) as a special case? Reproduce code: --------------- test.php <?php namespace My\NS; use My\NS; class A { public function test(A $obj = null) { var_dump($obj); } } ?> i don't think it easy to make a reproduce code, because in case 1: ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION is disabled until you change it in extension or patch php for testing and in case 2: even if you enable ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION, php is still free to access EG(zend_constants), EG(zend_constants) has to be empty to see the bug. see "actual result" there's a simple patch to reproduce it. (not fix) Index: zend_language_scanner.l =================================================================== RCS file: /repository/ZendEngine2/zend_language_scanner.l,v retrieving revision 1.131.2.11.2.13.2.32 diff -u -r1.131.2.11.2.13.2.32 zend_language_scanner.l --- zend_language_scanner.l 4 Nov 2008 15:58:51 -0000 1.131.2.11.2.13.2.32 +++ zend_language_scanner.l 12 Dec 2008 14:54:47 -0000 @@ -311,6 +311,8 @@ ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) { + HashTable empty_hash, *old_hash; + zend_lex_state original_lex_state; zend_op_array *op_array = (zend_op_array *) emalloc(sizeof(zend_op_array)); zend_op_array *original_active_op_array = CG(active_op_array); @@ -320,6 +322,12 @@ znode retval_znode; zend_bool original_in_compilation = CG(in_compilation); + CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION; + zend_hash_init(&empty_hash, 1, NULL, NULL, 0); + old_hash = EG(zend_constants); + EG(zend_constants) = &empty_hash; + fprintf(stderr, "asdfasdf\n\n"); + retval_znode.op_type = IS_CONST; retval_znode.u.constant.type = IS_LONG; retval_znode.u.constant.value.lval = 1; @@ -364,6 +372,10 @@ if (compilation_successful) { zend_restore_lexical_state(&original_lex_state TSRMLS_CC); } + + zend_hash_destroy(&empty_hash); + EG(zend_constants) = old_hash; + return retval; } Expected result: ---------------- in case 1: when ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION is enabled, "null" (code) should not be resolved to "null" (value, which is IS_NULL) at compile time, and should be resolve at runtime. in case 2: at compile time, php should behavoir the same regardless to what EG(zend_constants). when EG(zend_constants) is empty, it should not raise ""Default value for parameters with a class type hint can only be NULL" for the reproduce code above -- Edit bug report at http://bugs.php.net/?id=46850&edit=1 -- Try a CVS snapshot (PHP 5.2): http://bugs.php.net/fix.php?id=46850&r=trysnapshot52 Try a CVS snapshot (PHP 5.3): http://bugs.php.net/fix.php?id=46850&r=trysnapshot53 Try a CVS snapshot (PHP 6.0): http://bugs.php.net/fix.php?id=46850&r=trysnapshot60 Fixed in CVS: http://bugs.php.net/fix.php?id=46850&r=fixedcvs Fixed in CVS and need be documented: http://bugs.php.net/fix.php?id=46850&r=needdocs Fixed in release: http://bugs.php.net/fix.php?id=46850&r=alreadyfixed Need backtrace: http://bugs.php.net/fix.php?id=46850&r=needtrace Need Reproduce Script: http://bugs.php.net/fix.php?id=46850&r=needscript Try newer version: http://bugs.php.net/fix.php?id=46850&r=oldversion Not developer issue: http://bugs.php.net/fix.php?id=46850&r=support Expected behavior: http://bugs.php.net/fix.php?id=46850&r=notwrong Not enough info: http://bugs.php.net/fix.php?id=46850&r=notenoughinfo Submitted twice: http://bugs.php.net/fix.php?id=46850&r=submittedtwice register_globals: http://bugs.php.net/fix.php?id=46850&r=globals PHP 4 support discontinued: http://bugs.php.net/fix.php?id=46850&r=php4 Daylight Savings: http://bugs.php.net/fix.php?id=46850&r=dst IIS Stability: http://bugs.php.net/fix.php?id=46850&r=isapi Install GNU Sed: http://bugs.php.net/fix.php?id=46850&r=gnused Floating point limitations: http://bugs.php.net/fix.php?id=46850&r=float No Zend Extensions: http://bugs.php.net/fix.php?id=46850&r=nozend MySQL Configuration Error: http://bugs.php.net/fix.php?id=46850&r=mysqlcfg