From 5dd41627bed892e76492ae3945e3b0d9cac21019 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Tue, 16 Jul 2013 20:39:33 +0200 Subject: [PATCH 01/26] Add new 'use function' sequence for importing namespaced functions This is specified as the use_function RFC: * https://wiki.php.net/rfc/use_function --- Zend/tests/use_function/alias.phpt | 30 ++++++++ Zend/tests/use_function/basic.phpt | 26 +++++++ Zend/tests/use_function/conflicting_use.phpt | 25 ++++++ .../use_function/no_global_fallback.phpt | 18 +++++ Zend/tests/use_function/shadow_core.phpt | 26 +++++++ Zend/tests/use_function/shadow_global.phpt | 32 ++++++++ .../use_function/shadow_global_same_ns.phpt | 25 ++++++ Zend/zend_compile.c | 77 +++++++++++++++++++ Zend/zend_compile.h | 1 + Zend/zend_globals.h | 1 + Zend/zend_language_parser.y | 13 ++++ 11 files changed, 274 insertions(+) create mode 100644 Zend/tests/use_function/alias.phpt create mode 100644 Zend/tests/use_function/basic.phpt create mode 100644 Zend/tests/use_function/conflicting_use.phpt create mode 100644 Zend/tests/use_function/no_global_fallback.phpt create mode 100644 Zend/tests/use_function/shadow_core.phpt create mode 100644 Zend/tests/use_function/shadow_global.phpt create mode 100644 Zend/tests/use_function/shadow_global_same_ns.phpt diff --git a/Zend/tests/use_function/alias.phpt b/Zend/tests/use_function/alias.phpt new file mode 100644 index 00000000000..5f7e97fff87 --- /dev/null +++ b/Zend/tests/use_function/alias.phpt @@ -0,0 +1,30 @@ +--TEST-- +aliasing imported functions to resolve naming conflicts +--FILE-- + +--EXPECT-- +string(7) "foo.baz" +string(7) "bar.baz" +Done diff --git a/Zend/tests/use_function/basic.phpt b/Zend/tests/use_function/basic.phpt new file mode 100644 index 00000000000..513a96620c1 --- /dev/null +++ b/Zend/tests/use_function/basic.phpt @@ -0,0 +1,26 @@ +--TEST-- +import namespaced function +--FILE-- + +--EXPECT-- +string(11) "foo.bar.baz" +string(11) "foo.bar.baz" +Done diff --git a/Zend/tests/use_function/conflicting_use.phpt b/Zend/tests/use_function/conflicting_use.phpt new file mode 100644 index 00000000000..ed531e4febe --- /dev/null +++ b/Zend/tests/use_function/conflicting_use.phpt @@ -0,0 +1,25 @@ +--TEST-- +use function statements with conflicting names +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use bar\baz as baz because the name is already in use in %s on line %d diff --git a/Zend/tests/use_function/no_global_fallback.phpt b/Zend/tests/use_function/no_global_fallback.phpt new file mode 100644 index 00000000000..018ae92afc0 --- /dev/null +++ b/Zend/tests/use_function/no_global_fallback.phpt @@ -0,0 +1,18 @@ +--TEST-- +non-existent imported functions should not be looked up in the global table +--FILE-- + +--EXPECTF-- +Fatal error: Call to undefined function foo\bar\baz() in %s on line %d diff --git a/Zend/tests/use_function/shadow_core.phpt b/Zend/tests/use_function/shadow_core.phpt new file mode 100644 index 00000000000..b06fbfce2e1 --- /dev/null +++ b/Zend/tests/use_function/shadow_core.phpt @@ -0,0 +1,26 @@ +--TEST-- +shadowing a global core function with a local version +--FILE-- + +--EXPECT-- +int(11) +int(4) +Done diff --git a/Zend/tests/use_function/shadow_global.phpt b/Zend/tests/use_function/shadow_global.phpt new file mode 100644 index 00000000000..b3182993b37 --- /dev/null +++ b/Zend/tests/use_function/shadow_global.phpt @@ -0,0 +1,32 @@ +--TEST-- +shadowing a global function with a local version +--FILE-- + +--EXPECT-- +string(10) "global bar" +string(9) "local bar" +Done diff --git a/Zend/tests/use_function/shadow_global_same_ns.phpt b/Zend/tests/use_function/shadow_global_same_ns.phpt new file mode 100644 index 00000000000..7a30c8238f3 --- /dev/null +++ b/Zend/tests/use_function/shadow_global_same_ns.phpt @@ -0,0 +1,25 @@ +--TEST-- +shadowing global functions defined in the same namespace as use +--FILE-- + +--EXPECT-- +string(5) "local" +Done diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f250b2be208..7696960c204 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -204,6 +204,7 @@ void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */ CG(in_namespace) = 0; CG(has_bracketed_namespaces) = 0; CG(current_import) = NULL; + CG(current_import_function) = NULL; init_compiler_declarables(TSRMLS_C); zend_stack_init(&CG(context_stack)); @@ -2094,6 +2095,20 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace return; } + if (CG(current_import_function)) { + len = Z_STRLEN(element_name->u.constant)+1; + lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); + /* Check if function matches imported name */ + if (zend_hash_find(CG(current_import_function), lcname, len, (void**)&ns) == SUCCESS) { + zval_dtor(&element_name->u.constant); + element_name->u.constant = **ns; + zval_copy_ctor(&element_name->u.constant); + efree(lcname); + return; + } + efree(lcname); + } + if (compound && CG(current_import)) { len = compound - Z_STRVAL(element_name->u.constant); lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); @@ -6997,6 +7012,12 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_bracket TSRMLS_DC CG(current_import) = NULL; } + if (CG(current_import_function)) { + zend_hash_destroy(CG(current_import_function)); + efree(CG(current_import_function)); + CG(current_import_function) = NULL; + } + if (CG(doc_comment)) { efree(CG(doc_comment)); CG(doc_comment) = NULL; @@ -7089,6 +7110,57 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ } /* }}} */ +void zend_do_use_function(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{{ */ +{ + char *lcname; + zval *name, *ns, tmp; + zend_bool warn = 0; + + if (!CG(current_import_function)) { + CG(current_import_function) = emalloc(sizeof(HashTable)); + zend_hash_init(CG(current_import_function), 0, NULL, ZVAL_PTR_DTOR, 0); + } + + ALLOC_ZVAL(ns); + *ns = ns_name->u.constant; + if (new_name) { + name = &new_name->u.constant; + } else { + const char *p; + + /* The form "use A\B" is eqivalent to "use A\B as B". + So we extract the last part of compound name to use as a new_name */ + name = &tmp; + p = zend_memrchr(Z_STRVAL_P(ns), '\\', Z_STRLEN_P(ns)); + if (p) { + ZVAL_STRING(name, p+1, 1); + } else { + *name = *ns; + zval_copy_ctor(name); + warn = !is_global && !CG(current_namespace); + } + } + + lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name)); + + if (((Z_STRLEN_P(name) == sizeof("self")-1) && + !memcmp(lcname, "self", sizeof("self")-1)) || + ((Z_STRLEN_P(name) == sizeof("parent")-1) && + !memcmp(lcname, "parent", sizeof("parent")-1))) { + zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name)); + } + + if (zend_hash_add(CG(current_import_function), lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { + zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name)); + } + if (warn) { + zend_error(E_WARNING, "The use statement with non-compound name '%s' has no effect", Z_STRVAL_P(name)); + } + efree(lcname); + zval_dtor(name); +} +/* }}} */ + void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */ { zend_op *opline; @@ -7141,6 +7213,11 @@ void zend_do_end_namespace(TSRMLS_D) /* {{{ */ efree(CG(current_import)); CG(current_import) = NULL; } + if (CG(current_import_function)) { + zend_hash_destroy(CG(current_import_function)); + efree(CG(current_import_function)); + CG(current_import_function) = NULL; + } } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 9c55b5ebe88..f2078ed85b6 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -636,6 +636,7 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_brackets TSRMLS_D void zend_do_end_namespace(TSRMLS_D); void zend_verify_namespace(TSRMLS_D); void zend_do_use(znode *name, znode *new_name, int is_global TSRMLS_DC); +void zend_do_use_function(znode *name, znode *new_name, int is_global TSRMLS_DC); void zend_do_end_compilation(TSRMLS_D); void zend_do_resolve_class_name(znode *result, znode *class_name, int is_static TSRMLS_DC); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index b9a5b39914a..2a1194affc6 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -131,6 +131,7 @@ struct _zend_compiler_globals { zval *current_namespace; HashTable *current_import; + HashTable *current_import_function; zend_bool in_namespace; zend_bool has_bracketed_namespaces; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 6a9a24a87ea..df3e55f95fb 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -240,6 +240,7 @@ top_statement: | T_NAMESPACE '{' { zend_do_begin_namespace(NULL, 1 TSRMLS_CC); } top_statement_list '}' { zend_do_end_namespace(TSRMLS_C); } | T_USE use_declarations ';' { zend_verify_namespace(TSRMLS_C); } + | T_USE T_FUNCTION use_function_declarations ';' { zend_verify_namespace(TSRMLS_C); } | constant_declaration ';' { zend_verify_namespace(TSRMLS_C); } ; @@ -255,6 +256,18 @@ use_declaration: | T_NS_SEPARATOR namespace_name T_AS T_STRING { zend_do_use(&$2, &$4, 1 TSRMLS_CC); } ; +use_function_declarations: + use_function_declarations ',' use_function_declaration + | use_function_declaration +; + +use_function_declaration: + namespace_name { zend_do_use_function(&$1, NULL, 0 TSRMLS_CC); } + | namespace_name T_AS T_STRING { zend_do_use_function(&$1, &$3, 0 TSRMLS_CC); } + | T_NS_SEPARATOR namespace_name { zend_do_use_function(&$2, NULL, 1 TSRMLS_CC); } + | T_NS_SEPARATOR namespace_name T_AS T_STRING { zend_do_use_function(&$2, &$4, 1 TSRMLS_CC); } +; + constant_declaration: constant_declaration ',' T_STRING '=' static_scalar { zend_do_declare_constant(&$3, &$5 TSRMLS_CC); } | T_CONST T_STRING '=' static_scalar { zend_do_declare_constant(&$2, &$4 TSRMLS_CC); } From e1125a6a894a8b005aaea6b8ce2e0ea6bf39e483 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Tue, 23 Jul 2013 21:08:49 +0200 Subject: [PATCH 02/26] Correctly distinguish between functions and constants So far 'use function' applied to both constants and functions. This patch correctly separates the two. --- Zend/tests/use_function/ignore_constants.phpt | 23 ++++++++++++++++++ Zend/zend_compile.c | 24 ++++++++++++++----- Zend/zend_compile.h | 4 +++- 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 Zend/tests/use_function/ignore_constants.phpt diff --git a/Zend/tests/use_function/ignore_constants.phpt b/Zend/tests/use_function/ignore_constants.phpt new file mode 100644 index 00000000000..c50ff7357af --- /dev/null +++ b/Zend/tests/use_function/ignore_constants.phpt @@ -0,0 +1,23 @@ +--TEST-- +use function should ignore namespaced constants +--FILE-- + +--EXPECT-- +int(43) +Done diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 7696960c204..8013a1e5d19 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1938,7 +1938,7 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace char *lcname; char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant)); - zend_resolve_non_class_name(function_name, check_namespace TSRMLS_CC); + zend_resolve_function_name(function_name, check_namespace TSRMLS_CC); if (check_namespace && CG(current_namespace) && !is_compound) { /* We assume we call function from the current namespace @@ -2077,7 +2077,7 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML } /* }}} */ -void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ +void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, HashTable *current_import_sub TSRMLS_DC) /* {{{ */ { znode tmp; int len; @@ -2095,11 +2095,11 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace return; } - if (CG(current_import_function)) { + if (current_import_sub) { len = Z_STRLEN(element_name->u.constant)+1; lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); /* Check if function matches imported name */ - if (zend_hash_find(CG(current_import_function), lcname, len, (void**)&ns) == SUCCESS) { + if (zend_hash_find(current_import_sub, lcname, len, (void**)&ns) == SUCCESS) { zval_dtor(&element_name->u.constant); element_name->u.constant = **ns; zval_copy_ctor(&element_name->u.constant); @@ -2142,6 +2142,18 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace } /* }}} */ +void zend_resolve_function_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ +{ + zend_resolve_non_class_name(element_name, check_namespace, CG(current_import_function) TSRMLS_CC); +} +/* }}} */ + +void zend_resolve_const_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ +{ + zend_resolve_non_class_name(element_name, check_namespace, NULL TSRMLS_CC); +} +/* }}} */ + void zend_do_resolve_class_name(znode *result, znode *class_name, int is_static TSRMLS_DC) /* {{{ */ { char *lcname; @@ -5644,7 +5656,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con break; } - zend_resolve_non_class_name(constant_name, check_namespace TSRMLS_CC); + zend_resolve_const_name(constant_name, check_namespace TSRMLS_CC); if(!compound) { fetch_type |= IS_CONSTANT_UNQUALIFIED; @@ -5656,7 +5668,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con case ZEND_RT: compound = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant)); - zend_resolve_non_class_name(constant_name, check_namespace TSRMLS_CC); + zend_resolve_const_name(constant_name, check_namespace TSRMLS_CC); if(zend_constant_ct_subst(result, &constant_name->u.constant, 1 TSRMLS_CC)) { break; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index f2078ed85b6..066c517089d 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -437,7 +437,9 @@ ZEND_API char *zend_get_compiled_filename(TSRMLS_D); ZEND_API int zend_get_compiled_lineno(TSRMLS_D); ZEND_API size_t zend_get_scanned_file_offset(TSRMLS_D); -void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace TSRMLS_DC); +void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, HashTable *current_import_sub TSRMLS_DC); +void zend_resolve_function_name(znode *element_name, zend_bool check_namespace TSRMLS_DC); +void zend_resolve_const_name(znode *element_name, zend_bool check_namespace TSRMLS_DC); void zend_resolve_class_name(znode *class_name, ulong fetch_type, int check_ns_name TSRMLS_DC); ZEND_API const char* zend_get_compiled_variable_name(const zend_op_array *op_array, zend_uint var, int* name_len); From 4adf49eeaffc23cc6f4be53c2d89c720bd96d0c3 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Tue, 23 Jul 2013 20:21:48 +0200 Subject: [PATCH 03/26] Import namespaced constants via new 'use const' sequence --- Zend/tests/use_const/alias.phpt | 26 ++++++++++ Zend/tests/use_const/basic.phpt | 22 +++++++++ Zend/tests/use_const/conflicting_use.phpt | 21 +++++++++ Zend/tests/use_const/function_and_cons.phpt | 25 ++++++++++ Zend/tests/use_const/no_global_fallback.phpt | 18 +++++++ Zend/tests/use_const/shadow_core.phpt | 24 ++++++++++ Zend/tests/use_const/shadow_core_null.phpt | 12 +++++ Zend/tests/use_const/shadow_global.phpt | 28 +++++++++++ .../use_const/shadow_global_same_ns.phpt | 21 +++++++++ Zend/zend_compile.c | 47 +++++++++++++++---- Zend/zend_compile.h | 2 + Zend/zend_globals.h | 1 + Zend/zend_language_parser.y | 13 +++++ 13 files changed, 251 insertions(+), 9 deletions(-) create mode 100644 Zend/tests/use_const/alias.phpt create mode 100644 Zend/tests/use_const/basic.phpt create mode 100644 Zend/tests/use_const/conflicting_use.phpt create mode 100644 Zend/tests/use_const/function_and_cons.phpt create mode 100644 Zend/tests/use_const/no_global_fallback.phpt create mode 100644 Zend/tests/use_const/shadow_core.phpt create mode 100644 Zend/tests/use_const/shadow_core_null.phpt create mode 100644 Zend/tests/use_const/shadow_global.phpt create mode 100644 Zend/tests/use_const/shadow_global_same_ns.phpt diff --git a/Zend/tests/use_const/alias.phpt b/Zend/tests/use_const/alias.phpt new file mode 100644 index 00000000000..f179393006b --- /dev/null +++ b/Zend/tests/use_const/alias.phpt @@ -0,0 +1,26 @@ +--TEST-- +aliasing imported constants to resolve naming conflicts +--FILE-- + +--EXPECT-- +int(42) +int(43) +Done diff --git a/Zend/tests/use_const/basic.phpt b/Zend/tests/use_const/basic.phpt new file mode 100644 index 00000000000..6eaed7f27d3 --- /dev/null +++ b/Zend/tests/use_const/basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +import namespaced constant +--FILE-- + +--EXPECT-- +int(42) +int(43) +Done diff --git a/Zend/tests/use_const/conflicting_use.phpt b/Zend/tests/use_const/conflicting_use.phpt new file mode 100644 index 00000000000..f873fdcc653 --- /dev/null +++ b/Zend/tests/use_const/conflicting_use.phpt @@ -0,0 +1,21 @@ +--TEST-- +use const statements with conflicting names +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use bar\baz as baz because the name is already in use in %s on line %d diff --git a/Zend/tests/use_const/function_and_cons.phpt b/Zend/tests/use_const/function_and_cons.phpt new file mode 100644 index 00000000000..6c975ba923c --- /dev/null +++ b/Zend/tests/use_const/function_and_cons.phpt @@ -0,0 +1,25 @@ +--TEST-- +use function and use const in the same block +--FILE-- + +--EXPECT-- +string(11) "local const" +string(14) "local function" +Done diff --git a/Zend/tests/use_const/no_global_fallback.phpt b/Zend/tests/use_const/no_global_fallback.phpt new file mode 100644 index 00000000000..fad18797ba6 --- /dev/null +++ b/Zend/tests/use_const/no_global_fallback.phpt @@ -0,0 +1,18 @@ +--TEST-- +non-existent imported constants should not be looked up in the global table +--FILE-- + +--EXPECTF-- +Notice: Use of undefined constant baz - assumed 'baz' in %s on line %d +string(3) "baz" diff --git a/Zend/tests/use_const/shadow_core.phpt b/Zend/tests/use_const/shadow_core.phpt new file mode 100644 index 00000000000..8052baebc65 --- /dev/null +++ b/Zend/tests/use_const/shadow_core.phpt @@ -0,0 +1,24 @@ +--TEST-- +shadowing a global core constant with a local version +--FILE-- + +--EXPECTF-- +string(%d) "%s" +int(42) +Done diff --git a/Zend/tests/use_const/shadow_core_null.phpt b/Zend/tests/use_const/shadow_core_null.phpt new file mode 100644 index 00000000000..5bbc9329dfd --- /dev/null +++ b/Zend/tests/use_const/shadow_core_null.phpt @@ -0,0 +1,12 @@ +--TEST-- +shadowing null with a local version +--FILE-- + +--EXPECTF-- +Fatal error: Cannot redeclare constant 'null' in %s on line %d diff --git a/Zend/tests/use_const/shadow_global.phpt b/Zend/tests/use_const/shadow_global.phpt new file mode 100644 index 00000000000..ddd47a264c0 --- /dev/null +++ b/Zend/tests/use_const/shadow_global.phpt @@ -0,0 +1,28 @@ +--TEST-- +shadowing a global constant with a local version +--FILE-- + +--EXPECT-- +string(10) "global bar" +string(9) "local bar" +Done diff --git a/Zend/tests/use_const/shadow_global_same_ns.phpt b/Zend/tests/use_const/shadow_global_same_ns.phpt new file mode 100644 index 00000000000..7e8a8710277 --- /dev/null +++ b/Zend/tests/use_const/shadow_global_same_ns.phpt @@ -0,0 +1,21 @@ +--TEST-- +shadowing global constants defined in the same namespace as use +--FILE-- + +--EXPECT-- +string(5) "local" +Done diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 8013a1e5d19..2660781e603 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -205,6 +205,7 @@ void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */ CG(has_bracketed_namespaces) = 0; CG(current_import) = NULL; CG(current_import_function) = NULL; + CG(current_import_const) = NULL; init_compiler_declarables(TSRMLS_C); zend_stack_init(&CG(context_stack)); @@ -2098,7 +2099,7 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, if (current_import_sub) { len = Z_STRLEN(element_name->u.constant)+1; lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); - /* Check if function matches imported name */ + /* Check if function/const matches imported name */ if (zend_hash_find(current_import_sub, lcname, len, (void**)&ns) == SUCCESS) { zval_dtor(&element_name->u.constant); element_name->u.constant = **ns; @@ -2150,7 +2151,7 @@ void zend_resolve_function_name(znode *element_name, zend_bool check_namespace T void zend_resolve_const_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ { - zend_resolve_non_class_name(element_name, check_namespace, NULL TSRMLS_CC); + zend_resolve_non_class_name(element_name, check_namespace, CG(current_import_const) TSRMLS_CC); } /* }}} */ @@ -7030,6 +7031,12 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_bracket TSRMLS_DC CG(current_import_function) = NULL; } + if (CG(current_import_const)) { + zend_hash_destroy(CG(current_import_const)); + efree(CG(current_import_const)); + CG(current_import_const) = NULL; + } + if (CG(doc_comment)) { efree(CG(doc_comment)); CG(doc_comment) = NULL; @@ -7122,17 +7129,12 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ } /* }}} */ -void zend_do_use_function(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{{ */ +void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, HashTable *current_import_sub TSRMLS_DC) /* {{{ */ { char *lcname; zval *name, *ns, tmp; zend_bool warn = 0; - if (!CG(current_import_function)) { - CG(current_import_function) = emalloc(sizeof(HashTable)); - zend_hash_init(CG(current_import_function), 0, NULL, ZVAL_PTR_DTOR, 0); - } - ALLOC_ZVAL(ns); *ns = ns_name->u.constant; if (new_name) { @@ -7162,7 +7164,7 @@ void zend_do_use_function(znode *ns_name, znode *new_name, int is_global TSRMLS_ zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name)); } - if (zend_hash_add(CG(current_import_function), lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { + if (zend_hash_add(current_import_sub, lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name)); } if (warn) { @@ -7173,6 +7175,28 @@ void zend_do_use_function(znode *ns_name, znode *new_name, int is_global TSRMLS_ } /* }}} */ +void zend_do_use_function(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{{ */ +{ + if (!CG(current_import_function)) { + CG(current_import_function) = emalloc(sizeof(HashTable)); + zend_hash_init(CG(current_import_function), 0, NULL, ZVAL_PTR_DTOR, 0); + } + + zend_do_use_non_class(ns_name, new_name, is_global, CG(current_import_function) TSRMLS_CC); +} +/* }}} */ + +void zend_do_use_const(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{{ */ +{ + if (!CG(current_import_const)) { + CG(current_import_const) = emalloc(sizeof(HashTable)); + zend_hash_init(CG(current_import_const), 0, NULL, ZVAL_PTR_DTOR, 0); + } + + zend_do_use_non_class(ns_name, new_name, is_global, CG(current_import_const) TSRMLS_CC); +} +/* }}} */ + void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */ { zend_op *opline; @@ -7230,6 +7254,11 @@ void zend_do_end_namespace(TSRMLS_D) /* {{{ */ efree(CG(current_import_function)); CG(current_import_function) = NULL; } + if (CG(current_import_const)) { + zend_hash_destroy(CG(current_import_const)); + efree(CG(current_import_const)); + CG(current_import_const) = NULL; + } } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 066c517089d..3c944e45a6d 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -638,7 +638,9 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_brackets TSRMLS_D void zend_do_end_namespace(TSRMLS_D); void zend_verify_namespace(TSRMLS_D); void zend_do_use(znode *name, znode *new_name, int is_global TSRMLS_DC); +void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, HashTable *current_import_sub TSRMLS_DC); void zend_do_use_function(znode *name, znode *new_name, int is_global TSRMLS_DC); +void zend_do_use_const(znode *name, znode *new_name, int is_global TSRMLS_DC); void zend_do_end_compilation(TSRMLS_D); void zend_do_resolve_class_name(znode *result, znode *class_name, int is_static TSRMLS_DC); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 2a1194affc6..ddb5fc5df74 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -132,6 +132,7 @@ struct _zend_compiler_globals { zval *current_namespace; HashTable *current_import; HashTable *current_import_function; + HashTable *current_import_const; zend_bool in_namespace; zend_bool has_bracketed_namespaces; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index df3e55f95fb..7cfab914deb 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -241,6 +241,7 @@ top_statement: top_statement_list '}' { zend_do_end_namespace(TSRMLS_C); } | T_USE use_declarations ';' { zend_verify_namespace(TSRMLS_C); } | T_USE T_FUNCTION use_function_declarations ';' { zend_verify_namespace(TSRMLS_C); } + | T_USE T_CONST use_const_declarations ';' { zend_verify_namespace(TSRMLS_C); } | constant_declaration ';' { zend_verify_namespace(TSRMLS_C); } ; @@ -268,6 +269,18 @@ use_function_declaration: | T_NS_SEPARATOR namespace_name T_AS T_STRING { zend_do_use_function(&$2, &$4, 1 TSRMLS_CC); } ; +use_const_declarations: + use_const_declarations ',' use_const_declaration + | use_const_declaration +; + +use_const_declaration: + namespace_name { zend_do_use_const(&$1, NULL, 0 TSRMLS_CC); } + | namespace_name T_AS T_STRING { zend_do_use_const(&$1, &$3, 0 TSRMLS_CC); } + | T_NS_SEPARATOR namespace_name { zend_do_use_const(&$2, NULL, 1 TSRMLS_CC); } + | T_NS_SEPARATOR namespace_name T_AS T_STRING { zend_do_use_const(&$2, &$4, 1 TSRMLS_CC); } +; + constant_declaration: constant_declaration ',' T_STRING '=' static_scalar { zend_do_declare_constant(&$3, &$5 TSRMLS_CC); } | T_CONST T_STRING '=' static_scalar { zend_do_declare_constant(&$2, &$4 TSRMLS_CC); } From 2dbbb8ae4b8f20f68c4d9f0f708d4391bbf49d07 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Wed, 21 Aug 2013 16:31:17 +0200 Subject: [PATCH 04/26] Add test case for conflicting use and use function alias (stas) --- .../use_function/conflicting_use_alias.phpt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Zend/tests/use_function/conflicting_use_alias.phpt diff --git a/Zend/tests/use_function/conflicting_use_alias.phpt b/Zend/tests/use_function/conflicting_use_alias.phpt new file mode 100644 index 00000000000..2870512014d --- /dev/null +++ b/Zend/tests/use_function/conflicting_use_alias.phpt @@ -0,0 +1,20 @@ +--TEST-- +use and use function with the same alias +--FILE-- + +--EXPECT-- +string(3) "foo" From 6b385ebc85ea8f01db726fbf06b82b4587fee332 Mon Sep 17 00:00:00 2001 From: Danack Date: Thu, 22 Aug 2013 02:24:59 +0100 Subject: [PATCH 05/26] Removed assumption that \\ will be present The function zend_add_ns_func_name_literal is called if the parser finds a function that is not in the global or current namespace. It assumes such a function will have a \\ in it, which is no longer true with the use function patch. The code change above removes that assumption and makes the test work: PASS use and use function with the same alias [Zend/tests/use_function/conflicting_use_alias.phpt] --- Zend/zend_compile.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 2660781e603..8725083d5be 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -426,12 +426,16 @@ int zend_add_ns_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC); CALCULATE_LITERAL_HASH(lc_literal); - ns_separator = (const char*)zend_memrchr(Z_STRVAL_P(zv), '\\', Z_STRLEN_P(zv)) + 1; - lc_len = Z_STRLEN_P(zv) - (ns_separator - Z_STRVAL_P(zv)); - lc_name = zend_str_tolower_dup(ns_separator, lc_len); - ZVAL_STRINGL(&c, lc_name, lc_len, 0); - lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC); - CALCULATE_LITERAL_HASH(lc_literal); + ns_separator = (const char*)zend_memrchr(Z_STRVAL_P(zv), '\\', Z_STRLEN_P(zv)); + + if (ns_separator != NULL) { + ns_separator += 1; + lc_len = Z_STRLEN_P(zv) - (ns_separator - Z_STRVAL_P(zv)); + lc_name = zend_str_tolower_dup(ns_separator, lc_len); + ZVAL_STRINGL(&c, lc_name, lc_len, 0); + lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC); + CALCULATE_LITERAL_HASH(lc_literal); + } return ret; } From 31d77053a14f59748c12afce82d31fb880dbc962 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Thu, 22 Aug 2013 12:10:15 +0200 Subject: [PATCH 06/26] More test cases for conflicting aliases --- .../use_const/conflicting_use_alias.phpt | 18 +++++++++++++++ .../conflicting_use_const_alias.phpt | 23 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 Zend/tests/use_const/conflicting_use_alias.phpt create mode 100644 Zend/tests/use_function/conflicting_use_const_alias.phpt diff --git a/Zend/tests/use_const/conflicting_use_alias.phpt b/Zend/tests/use_const/conflicting_use_alias.phpt new file mode 100644 index 00000000000..91cd020968e --- /dev/null +++ b/Zend/tests/use_const/conflicting_use_alias.phpt @@ -0,0 +1,18 @@ +--TEST-- +use and use function with the same alias +--FILE-- + +--EXPECT-- +string(3) "foo" diff --git a/Zend/tests/use_function/conflicting_use_const_alias.phpt b/Zend/tests/use_function/conflicting_use_const_alias.phpt new file mode 100644 index 00000000000..b8472a58212 --- /dev/null +++ b/Zend/tests/use_function/conflicting_use_const_alias.phpt @@ -0,0 +1,23 @@ +--TEST-- +use and use function with the same alias +--FILE-- + +--EXPECT-- +string(9) "foo.const" +string(12) "foo.function" From 5b18530e8cc8635592cfb98da0ecbc045c83bfe6 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Thu, 22 Aug 2013 22:12:34 +0200 Subject: [PATCH 07/26] Add test cases for conflicting use and definition in same ns (stas) --- Zend/tests/use_const/define_imported.phpt | 14 +++++++++++ .../use_const/define_imported_before.phpt | 14 +++++++++++ .../use_const/shadow_global_same_ns.phpt | 21 ---------------- Zend/tests/use_function/define_imported.phpt | 14 +++++++++++ .../use_function/define_imported_before.phpt | 14 +++++++++++ .../use_function/shadow_global_same_ns.phpt | 25 ------------------- 6 files changed, 56 insertions(+), 46 deletions(-) create mode 100644 Zend/tests/use_const/define_imported.phpt create mode 100644 Zend/tests/use_const/define_imported_before.phpt delete mode 100644 Zend/tests/use_const/shadow_global_same_ns.phpt create mode 100644 Zend/tests/use_function/define_imported.phpt create mode 100644 Zend/tests/use_function/define_imported_before.phpt delete mode 100644 Zend/tests/use_function/shadow_global_same_ns.phpt diff --git a/Zend/tests/use_const/define_imported.phpt b/Zend/tests/use_const/define_imported.phpt new file mode 100644 index 00000000000..5eb44be64a0 --- /dev/null +++ b/Zend/tests/use_const/define_imported.phpt @@ -0,0 +1,14 @@ +--TEST-- +defining const with same name as imported should fail +--FILE-- + +--EXPECTF-- +Fatal error: Cannot declare const bar because the name is already in use in %s on line %d diff --git a/Zend/tests/use_const/define_imported_before.phpt b/Zend/tests/use_const/define_imported_before.phpt new file mode 100644 index 00000000000..19374a2c586 --- /dev/null +++ b/Zend/tests/use_const/define_imported_before.phpt @@ -0,0 +1,14 @@ +--TEST-- +using const with same name as defined should fail +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use const foo\bar as bar because the name is already in use in %s on line %d diff --git a/Zend/tests/use_const/shadow_global_same_ns.phpt b/Zend/tests/use_const/shadow_global_same_ns.phpt deleted file mode 100644 index 7e8a8710277..00000000000 --- a/Zend/tests/use_const/shadow_global_same_ns.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -shadowing global constants defined in the same namespace as use ---FILE-- - ---EXPECT-- -string(5) "local" -Done diff --git a/Zend/tests/use_function/define_imported.phpt b/Zend/tests/use_function/define_imported.phpt new file mode 100644 index 00000000000..c542a4d5494 --- /dev/null +++ b/Zend/tests/use_function/define_imported.phpt @@ -0,0 +1,14 @@ +--TEST-- +defining function with same name as imported should fail +--FILE-- + +--EXPECTF-- +Fatal error: Cannot declare function bar because the name is already in use in %s on line %d diff --git a/Zend/tests/use_function/define_imported_before.phpt b/Zend/tests/use_function/define_imported_before.phpt new file mode 100644 index 00000000000..ff5d5ca28d3 --- /dev/null +++ b/Zend/tests/use_function/define_imported_before.phpt @@ -0,0 +1,14 @@ +--TEST-- +using function with same name as defined should fail +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use function foo\bar as bar because the name is already in use in %s on line %d diff --git a/Zend/tests/use_function/shadow_global_same_ns.phpt b/Zend/tests/use_function/shadow_global_same_ns.phpt deleted file mode 100644 index 7a30c8238f3..00000000000 --- a/Zend/tests/use_function/shadow_global_same_ns.phpt +++ /dev/null @@ -1,25 +0,0 @@ ---TEST-- -shadowing global functions defined in the same namespace as use ---FILE-- - ---EXPECT-- -string(5) "local" -Done From 30f16c354060f730dbc321799613527e5a7ea00e Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Fri, 23 Aug 2013 23:39:42 +0200 Subject: [PATCH 08/26] Compile error on function definition conflicting with import --- Zend/zend_compile.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 8725083d5be..95723c92f1e 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -428,7 +428,7 @@ int zend_add_ns_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS ns_separator = (const char*)zend_memrchr(Z_STRVAL_P(zv), '\\', Z_STRLEN_P(zv)); - if (ns_separator != NULL) { + if (ns_separator != NULL) { ns_separator += 1; lc_len = Z_STRLEN_P(zv) - (ns_separator - Z_STRVAL_P(zv)); lc_name = zend_str_tolower_dup(ns_separator, lc_len); @@ -1701,6 +1701,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n } else { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); zval key; + zval **ns_name; if (CG(current_namespace)) { /* Prefix function name with current namespace name */ @@ -1716,6 +1717,19 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n lcname = zend_str_tolower_dup(name, name_len); } + /* Function name must not conflict with import names */ + if (CG(current_import_function) && + zend_hash_find(CG(current_import_function), lcname, Z_STRLEN(function_name->u.constant)+1, (void**)&ns_name) == SUCCESS) { + + char *tmp = zend_str_tolower_dup(Z_STRVAL_PP(ns_name), Z_STRLEN_PP(ns_name)); + + if (Z_STRLEN_PP(ns_name) != Z_STRLEN(function_name->u.constant) || + memcmp(tmp, lcname, Z_STRLEN(function_name->u.constant))) { + zend_error(E_COMPILE_ERROR, "Cannot declare function %s because the name is already in use", Z_STRVAL(function_name->u.constant)); + } + efree(tmp); + } + opline->opcode = ZEND_DECLARE_FUNCTION; opline->op1_type = IS_CONST; build_runtime_defined_function_key(&key, lcname, name_len TSRMLS_CC); From 85d4cfb00ddda70ae2418db283b0f53431ca62a8 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sat, 24 Aug 2013 23:53:43 +0200 Subject: [PATCH 09/26] Disallow using functions/consts defined in the same file * Keep track of defined function and const filenames * Prohibit use function foo if function foo exists * Prohibit use const foo if const foo exists --- Zend/tests/use_const/includes/foo_bar.php | 5 +++ .../use_const/includes/foo_php_version.php | 5 +++ Zend/tests/use_const/includes/global_bar.php | 3 ++ Zend/tests/use_const/includes/global_baz.php | 3 ++ Zend/tests/use_const/no_global_fallback.phpt | 10 ++--- Zend/tests/use_const/shadow_core.phpt | 16 ++------ Zend/tests/use_const/shadow_global.phpt | 7 +--- Zend/tests/use_function/includes/foo_bar.php | 7 ++++ .../use_function/includes/foo_strlen.php | 7 ++++ .../use_function/includes/global_bar.php | 5 +++ .../use_function/includes/global_baz.php | 4 ++ .../use_function/no_global_fallback.phpt | 11 ++--- Zend/tests/use_function/shadow_core.phpt | 18 ++------ Zend/tests/use_function/shadow_global.phpt | 11 +---- Zend/zend_compile.c | 41 +++++++++++++++++-- Zend/zend_compile.h | 2 +- Zend/zend_globals.h | 3 ++ 17 files changed, 99 insertions(+), 59 deletions(-) create mode 100644 Zend/tests/use_const/includes/foo_bar.php create mode 100644 Zend/tests/use_const/includes/foo_php_version.php create mode 100644 Zend/tests/use_const/includes/global_bar.php create mode 100644 Zend/tests/use_const/includes/global_baz.php create mode 100644 Zend/tests/use_function/includes/foo_bar.php create mode 100644 Zend/tests/use_function/includes/foo_strlen.php create mode 100644 Zend/tests/use_function/includes/global_bar.php create mode 100644 Zend/tests/use_function/includes/global_baz.php diff --git a/Zend/tests/use_const/includes/foo_bar.php b/Zend/tests/use_const/includes/foo_bar.php new file mode 100644 index 00000000000..90ed451f364 --- /dev/null +++ b/Zend/tests/use_const/includes/foo_bar.php @@ -0,0 +1,5 @@ + --EXPECTF-- diff --git a/Zend/tests/use_const/shadow_core.phpt b/Zend/tests/use_const/shadow_core.phpt index 8052baebc65..7d8bcbd1892 100644 --- a/Zend/tests/use_const/shadow_core.phpt +++ b/Zend/tests/use_const/shadow_core.phpt @@ -3,22 +3,14 @@ shadowing a global core constant with a local version --FILE-- --EXPECTF-- -string(%d) "%s" int(42) Done diff --git a/Zend/tests/use_const/shadow_global.phpt b/Zend/tests/use_const/shadow_global.phpt index ddd47a264c0..930cc9f0b87 100644 --- a/Zend/tests/use_const/shadow_global.phpt +++ b/Zend/tests/use_const/shadow_global.phpt @@ -4,11 +4,8 @@ shadowing a global constant with a local version --EXPECTF-- diff --git a/Zend/tests/use_function/shadow_core.phpt b/Zend/tests/use_function/shadow_core.phpt index b06fbfce2e1..8f92ff1e1be 100644 --- a/Zend/tests/use_function/shadow_core.phpt +++ b/Zend/tests/use_function/shadow_core.phpt @@ -3,24 +3,14 @@ shadowing a global core function with a local version --FILE-- --EXPECT-- -int(11) int(4) Done diff --git a/Zend/tests/use_function/shadow_global.phpt b/Zend/tests/use_function/shadow_global.phpt index b3182993b37..791bcdf4d50 100644 --- a/Zend/tests/use_function/shadow_global.phpt +++ b/Zend/tests/use_function/shadow_global.phpt @@ -4,15 +4,8 @@ shadowing a global function with a local version op2.constant); opline->extended_value = ZEND_DECLARE_FUNCTION; zend_hash_quick_update(CG(function_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); + zend_hash_add(&CG(function_filenames), lcname, strlen(lcname)+1, CG(compiled_filename), strlen(CG(compiled_filename))+1, NULL); zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context))); zend_init_compiler_context(TSRMLS_C); } @@ -7147,9 +7152,10 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ } /* }}} */ -void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, HashTable *current_import_sub TSRMLS_DC) /* {{{ */ +void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const char *type, HashTable *current_import_sub, HashTable *lookup_table TSRMLS_DC) /* {{{ */ { char *lcname; + char *filename; zval *name, *ns, tmp; zend_bool warn = 0; @@ -7182,6 +7188,33 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, HashT zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name)); } + if (CG(current_namespace)) { + /* Prefix import name with current namespace name to avoid conflicts with classes */ + char *c_ns_name = emalloc(Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) + 1); + + zend_str_tolower_copy(c_ns_name, Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace))); + c_ns_name[Z_STRLEN_P(CG(current_namespace))] = '\\'; + memcpy(c_ns_name+Z_STRLEN_P(CG(current_namespace))+1, lcname, Z_STRLEN_P(name)+1); + if (zend_hash_exists(lookup_table, c_ns_name, Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name)+1)) { + char *tmp2 = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); + + if (Z_STRLEN_P(ns) != Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) || + memcmp(tmp2, c_ns_name, Z_STRLEN_P(ns))) { + zend_error(E_COMPILE_ERROR, "Cannot use %s %s as %s because the name is already in use", type, Z_STRVAL_P(ns), Z_STRVAL_P(name)); + } + efree(tmp2); + } + efree(c_ns_name); + } else if (zend_hash_find(lookup_table, lcname, Z_STRLEN_P(name)+1, (void **)&filename) == SUCCESS && strcmp(filename, CG(compiled_filename)) == 0) { + char *c_tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); + + if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) || + memcmp(c_tmp, lcname, Z_STRLEN_P(ns))) { + zend_error(E_COMPILE_ERROR, "Cannot use %s %s as %s because the name is already in use", type, Z_STRVAL_P(ns), Z_STRVAL_P(name)); + } + efree(c_tmp); + } + if (zend_hash_add(current_import_sub, lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name)); } @@ -7200,7 +7233,7 @@ void zend_do_use_function(znode *ns_name, znode *new_name, int is_global TSRMLS_ zend_hash_init(CG(current_import_function), 0, NULL, ZVAL_PTR_DTOR, 0); } - zend_do_use_non_class(ns_name, new_name, is_global, CG(current_import_function) TSRMLS_CC); + zend_do_use_non_class(ns_name, new_name, is_global, "function", CG(current_import_function), &CG(function_filenames) TSRMLS_CC); } /* }}} */ @@ -7211,7 +7244,7 @@ void zend_do_use_const(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) zend_hash_init(CG(current_import_const), 0, NULL, ZVAL_PTR_DTOR, 0); } - zend_do_use_non_class(ns_name, new_name, is_global, CG(current_import_const) TSRMLS_CC); + zend_do_use_non_class(ns_name, new_name, is_global, "const", CG(current_import_const), &CG(const_filenames) TSRMLS_CC); } /* }}} */ @@ -7243,6 +7276,8 @@ void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */ SET_UNUSED(opline->result); SET_NODE(opline->op1, name); SET_NODE(opline->op2, value); + + zend_hash_add(&CG(const_filenames), Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant)+1, CG(compiled_filename), strlen(CG(compiled_filename))+1, NULL); } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 3c944e45a6d..8145b1cc9ba 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -638,7 +638,7 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_brackets TSRMLS_D void zend_do_end_namespace(TSRMLS_D); void zend_verify_namespace(TSRMLS_D); void zend_do_use(znode *name, znode *new_name, int is_global TSRMLS_DC); -void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, HashTable *current_import_sub TSRMLS_DC); +void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const char *type, HashTable *current_import_sub, HashTable *lookup_table TSRMLS_DC); void zend_do_use_function(znode *name, znode *new_name, int is_global TSRMLS_DC); void zend_do_use_const(znode *name, znode *new_name, int is_global TSRMLS_DC); void zend_do_end_compilation(TSRMLS_D); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index ddb5fc5df74..19c29c68f32 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -136,6 +136,9 @@ struct _zend_compiler_globals { zend_bool in_namespace; zend_bool has_bracketed_namespaces; + HashTable function_filenames; + HashTable const_filenames; + zend_compiler_context context; zend_stack context_stack; From 115c5ec7269c6dd7dfaeaa853a3a78a075d88e17 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sun, 25 Aug 2013 00:05:55 +0200 Subject: [PATCH 10/26] Compile error on const definition conflicting with import --- Zend/zend_compile.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 6770670d311..29d0760f600 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7251,6 +7251,7 @@ void zend_do_use_const(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */ { zend_op *opline; + zval **ns_name; if(Z_TYPE(value->u.constant) == IS_CONSTANT_ARRAY) { zend_error(E_COMPILE_ERROR, "Arrays are not allowed as constants"); @@ -7271,6 +7272,19 @@ void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */ *name = tmp; } + /* Constant name must not conflict with import names */ + if (CG(current_import_const) && + zend_hash_find(CG(current_import_const), Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant)+1, (void**)&ns_name) == SUCCESS) { + + char *tmp = zend_str_tolower_dup(Z_STRVAL_PP(ns_name), Z_STRLEN_PP(ns_name)); + + if (Z_STRLEN_PP(ns_name) != Z_STRLEN(name->u.constant) || + memcmp(tmp, Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant))) { + zend_error(E_COMPILE_ERROR, "Cannot declare const %s because the name is already in use", Z_STRVAL(name->u.constant)); + } + efree(tmp); + } + opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_DECLARE_CONST; SET_UNUSED(opline->result); From bc473228c83a6163350e0362ff3b0722f73b068c Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sun, 25 Aug 2013 14:03:07 +0200 Subject: [PATCH 11/26] Adjust some test names, remove obsolete and duplicate tests (nikic) --- .../use_const/conflicting_use_alias.phpt | 2 +- Zend/tests/use_const/function_and_cons.phpt | 25 ------------------- Zend/tests/use_const/shadow_core_null.phpt | 12 --------- .../conflicting_use_const_alias.phpt | 2 +- 4 files changed, 2 insertions(+), 39 deletions(-) delete mode 100644 Zend/tests/use_const/function_and_cons.phpt delete mode 100644 Zend/tests/use_const/shadow_core_null.phpt diff --git a/Zend/tests/use_const/conflicting_use_alias.phpt b/Zend/tests/use_const/conflicting_use_alias.phpt index 91cd020968e..8b563a4ca97 100644 --- a/Zend/tests/use_const/conflicting_use_alias.phpt +++ b/Zend/tests/use_const/conflicting_use_alias.phpt @@ -1,5 +1,5 @@ --TEST-- -use and use function with the same alias +use and use const with the same alias --FILE-- ---EXPECT-- -string(11) "local const" -string(14) "local function" -Done diff --git a/Zend/tests/use_const/shadow_core_null.phpt b/Zend/tests/use_const/shadow_core_null.phpt deleted file mode 100644 index 5bbc9329dfd..00000000000 --- a/Zend/tests/use_const/shadow_core_null.phpt +++ /dev/null @@ -1,12 +0,0 @@ ---TEST-- -shadowing null with a local version ---FILE-- - ---EXPECTF-- -Fatal error: Cannot redeclare constant 'null' in %s on line %d diff --git a/Zend/tests/use_function/conflicting_use_const_alias.phpt b/Zend/tests/use_function/conflicting_use_const_alias.phpt index b8472a58212..2e0faf0da21 100644 --- a/Zend/tests/use_function/conflicting_use_const_alias.phpt +++ b/Zend/tests/use_function/conflicting_use_const_alias.phpt @@ -1,5 +1,5 @@ --TEST-- -use and use function with the same alias +use const and use function with the same alias --FILE-- Date: Sun, 25 Aug 2013 15:08:26 +0200 Subject: [PATCH 12/26] self and parent are valid function and const names (nikic) --- Zend/tests/use_const/self_parent.phpt | 12 ++++++++++++ Zend/tests/use_function/self_parent.phpt | 12 ++++++++++++ Zend/zend_compile.c | 7 ------- 3 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 Zend/tests/use_const/self_parent.phpt create mode 100644 Zend/tests/use_function/self_parent.phpt diff --git a/Zend/tests/use_const/self_parent.phpt b/Zend/tests/use_const/self_parent.phpt new file mode 100644 index 00000000000..b71f2ecc81f --- /dev/null +++ b/Zend/tests/use_const/self_parent.phpt @@ -0,0 +1,12 @@ +--TEST-- +Allow self and parent in use const statement +--FILE-- + +--EXPECT-- diff --git a/Zend/tests/use_function/self_parent.phpt b/Zend/tests/use_function/self_parent.phpt new file mode 100644 index 00000000000..f1e1fa84f1d --- /dev/null +++ b/Zend/tests/use_function/self_parent.phpt @@ -0,0 +1,12 @@ +--TEST-- +Allow self and parent in use function statement +--FILE-- + +--EXPECT-- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 29d0760f600..b2367cbd244 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7181,13 +7181,6 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name)); - if (((Z_STRLEN_P(name) == sizeof("self")-1) && - !memcmp(lcname, "self", sizeof("self")-1)) || - ((Z_STRLEN_P(name) == sizeof("parent")-1) && - !memcmp(lcname, "parent", sizeof("parent")-1))) { - zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name)); - } - if (CG(current_namespace)) { /* Prefix import name with current namespace name to avoid conflicts with classes */ char *c_ns_name = emalloc(Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) + 1); From 28fa0896df908fd72c1766c5a6fe22d441e96494 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sun, 25 Aug 2013 15:09:19 +0200 Subject: [PATCH 13/26] Comment nitpick (nikic) --- Zend/zend_compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index b2367cbd244..bdb0e84dcf0 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7182,7 +7182,7 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name)); if (CG(current_namespace)) { - /* Prefix import name with current namespace name to avoid conflicts with classes */ + /* Prefix import name with current namespace name to avoid conflicts with functions/consts */ char *c_ns_name = emalloc(Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) + 1); zend_str_tolower_copy(c_ns_name, Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace))); From 6263f221ffeaa2a54b11249a40436b6f9bd6ca47 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sun, 25 Aug 2013 16:21:51 +0200 Subject: [PATCH 14/26] Handle case sensivity of constants (nikic) --- Zend/tests/use_const/case_sensivity.phpt | 12 ++++ Zend/tests/use_function/case_insensivity.phpt | 13 +++++ Zend/zend_compile.c | 58 +++++++++++-------- Zend/zend_compile.h | 4 +- 4 files changed, 62 insertions(+), 25 deletions(-) create mode 100644 Zend/tests/use_const/case_sensivity.phpt create mode 100644 Zend/tests/use_function/case_insensivity.phpt diff --git a/Zend/tests/use_const/case_sensivity.phpt b/Zend/tests/use_const/case_sensivity.phpt new file mode 100644 index 00000000000..1977daa93bb --- /dev/null +++ b/Zend/tests/use_const/case_sensivity.phpt @@ -0,0 +1,12 @@ +--TEST-- +importing const with same name but different case +--FILE-- + +--EXPECT-- diff --git a/Zend/tests/use_function/case_insensivity.phpt b/Zend/tests/use_function/case_insensivity.phpt new file mode 100644 index 00000000000..53ae3658a97 --- /dev/null +++ b/Zend/tests/use_function/case_insensivity.phpt @@ -0,0 +1,13 @@ +--TEST-- +importing function with same name but different case should fail +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use foo\BAR as BAR because the name is already in use in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index bdb0e84dcf0..623fe15fed4 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2101,12 +2101,12 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML } /* }}} */ -void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, HashTable *current_import_sub TSRMLS_DC) /* {{{ */ +void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, zend_bool case_sensitive, HashTable *current_import_sub TSRMLS_DC) /* {{{ */ { znode tmp; int len; zval **ns; - char *lcname, *compound = memchr(Z_STRVAL(element_name->u.constant), '\\', Z_STRLEN(element_name->u.constant)); + char *lookup_name, *compound = memchr(Z_STRVAL(element_name->u.constant), '\\', Z_STRLEN(element_name->u.constant)); if (Z_STRVAL(element_name->u.constant)[0] == '\\') { /* name starts with \ so it is known and unambiguos, nothing to do here but shorten it */ @@ -2121,23 +2121,31 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, if (current_import_sub) { len = Z_STRLEN(element_name->u.constant)+1; - lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); + if (case_sensitive) { + lookup_name = estrndup(Z_STRVAL(element_name->u.constant), len); + } else { + lookup_name = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); + } /* Check if function/const matches imported name */ - if (zend_hash_find(current_import_sub, lcname, len, (void**)&ns) == SUCCESS) { + if (zend_hash_find(current_import_sub, lookup_name, len, (void**)&ns) == SUCCESS) { zval_dtor(&element_name->u.constant); element_name->u.constant = **ns; zval_copy_ctor(&element_name->u.constant); - efree(lcname); + efree(lookup_name); return; } - efree(lcname); + efree(lookup_name); } if (compound && CG(current_import)) { len = compound - Z_STRVAL(element_name->u.constant); - lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); + if (case_sensitive) { + lookup_name = estrndup(Z_STRVAL(element_name->u.constant), len); + } else { + lookup_name = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); + } /* Check if first part of compound name is an import name */ - if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) { + if (zend_hash_find(CG(current_import), lookup_name, len+1, (void**)&ns) == SUCCESS) { /* Substitute import name */ tmp.op_type = IS_CONST; tmp.u.constant = **ns; @@ -2147,10 +2155,10 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+len, Z_STRLEN(element_name->u.constant)+1); zend_do_build_namespace_name(&tmp, &tmp, element_name TSRMLS_CC); *element_name = tmp; - efree(lcname); + efree(lookup_name); return; } - efree(lcname); + efree(lookup_name); } if (CG(current_namespace)) { @@ -2168,13 +2176,13 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, void zend_resolve_function_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ { - zend_resolve_non_class_name(element_name, check_namespace, CG(current_import_function) TSRMLS_CC); + zend_resolve_non_class_name(element_name, check_namespace, 0, CG(current_import_function) TSRMLS_CC); } /* }}} */ void zend_resolve_const_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ { - zend_resolve_non_class_name(element_name, check_namespace, CG(current_import_const) TSRMLS_CC); + zend_resolve_non_class_name(element_name, check_namespace, 1, CG(current_import_const) TSRMLS_CC); } /* }}} */ @@ -7152,9 +7160,9 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ } /* }}} */ -void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const char *type, HashTable *current_import_sub, HashTable *lookup_table TSRMLS_DC) /* {{{ */ +void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const char *type, zend_bool case_sensitive, HashTable *current_import_sub, HashTable *lookup_table TSRMLS_DC) /* {{{ */ { - char *lcname; + char *lookup_name; char *filename; zval *name, *ns, tmp; zend_bool warn = 0; @@ -7179,7 +7187,11 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const } } - lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name)); + if (case_sensitive) { + lookup_name = estrndup(Z_STRVAL_P(name), Z_STRLEN_P(name)); + } else { + lookup_name = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name)); + } if (CG(current_namespace)) { /* Prefix import name with current namespace name to avoid conflicts with functions/consts */ @@ -7187,7 +7199,7 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const zend_str_tolower_copy(c_ns_name, Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace))); c_ns_name[Z_STRLEN_P(CG(current_namespace))] = '\\'; - memcpy(c_ns_name+Z_STRLEN_P(CG(current_namespace))+1, lcname, Z_STRLEN_P(name)+1); + memcpy(c_ns_name+Z_STRLEN_P(CG(current_namespace))+1, lookup_name, Z_STRLEN_P(name)+1); if (zend_hash_exists(lookup_table, c_ns_name, Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name)+1)) { char *tmp2 = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); @@ -7198,23 +7210,23 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const efree(tmp2); } efree(c_ns_name); - } else if (zend_hash_find(lookup_table, lcname, Z_STRLEN_P(name)+1, (void **)&filename) == SUCCESS && strcmp(filename, CG(compiled_filename)) == 0) { + } else if (zend_hash_find(lookup_table, lookup_name, Z_STRLEN_P(name)+1, (void **)&filename) == SUCCESS && strcmp(filename, CG(compiled_filename)) == 0) { char *c_tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) || - memcmp(c_tmp, lcname, Z_STRLEN_P(ns))) { + memcmp(c_tmp, lookup_name, Z_STRLEN_P(ns))) { zend_error(E_COMPILE_ERROR, "Cannot use %s %s as %s because the name is already in use", type, Z_STRVAL_P(ns), Z_STRVAL_P(name)); } efree(c_tmp); } - if (zend_hash_add(current_import_sub, lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { + if (zend_hash_add(current_import_sub, lookup_name, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name)); } if (warn) { zend_error(E_WARNING, "The use statement with non-compound name '%s' has no effect", Z_STRVAL_P(name)); } - efree(lcname); + efree(lookup_name); zval_dtor(name); } /* }}} */ @@ -7226,7 +7238,7 @@ void zend_do_use_function(znode *ns_name, znode *new_name, int is_global TSRMLS_ zend_hash_init(CG(current_import_function), 0, NULL, ZVAL_PTR_DTOR, 0); } - zend_do_use_non_class(ns_name, new_name, is_global, "function", CG(current_import_function), &CG(function_filenames) TSRMLS_CC); + zend_do_use_non_class(ns_name, new_name, is_global, "function", 0, CG(current_import_function), &CG(function_filenames) TSRMLS_CC); } /* }}} */ @@ -7237,7 +7249,7 @@ void zend_do_use_const(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) zend_hash_init(CG(current_import_const), 0, NULL, ZVAL_PTR_DTOR, 0); } - zend_do_use_non_class(ns_name, new_name, is_global, "const", CG(current_import_const), &CG(const_filenames) TSRMLS_CC); + zend_do_use_non_class(ns_name, new_name, is_global, "const", 1, CG(current_import_const), &CG(const_filenames) TSRMLS_CC); } /* }}} */ @@ -7269,7 +7281,7 @@ void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */ if (CG(current_import_const) && zend_hash_find(CG(current_import_const), Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant)+1, (void**)&ns_name) == SUCCESS) { - char *tmp = zend_str_tolower_dup(Z_STRVAL_PP(ns_name), Z_STRLEN_PP(ns_name)); + char *tmp = estrndup(Z_STRVAL_PP(ns_name), Z_STRLEN_PP(ns_name)); if (Z_STRLEN_PP(ns_name) != Z_STRLEN(name->u.constant) || memcmp(tmp, Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant))) { diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 8145b1cc9ba..e8c0309319d 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -437,7 +437,7 @@ ZEND_API char *zend_get_compiled_filename(TSRMLS_D); ZEND_API int zend_get_compiled_lineno(TSRMLS_D); ZEND_API size_t zend_get_scanned_file_offset(TSRMLS_D); -void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, HashTable *current_import_sub TSRMLS_DC); +void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, zend_bool case_sensitive, HashTable *current_import_sub TSRMLS_DC); void zend_resolve_function_name(znode *element_name, zend_bool check_namespace TSRMLS_DC); void zend_resolve_const_name(znode *element_name, zend_bool check_namespace TSRMLS_DC); void zend_resolve_class_name(znode *class_name, ulong fetch_type, int check_ns_name TSRMLS_DC); @@ -638,7 +638,7 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_brackets TSRMLS_D void zend_do_end_namespace(TSRMLS_D); void zend_verify_namespace(TSRMLS_D); void zend_do_use(znode *name, znode *new_name, int is_global TSRMLS_DC); -void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const char *type, HashTable *current_import_sub, HashTable *lookup_table TSRMLS_DC); +void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const char *type, zend_bool case_sensitive, HashTable *current_import_sub, HashTable *lookup_table TSRMLS_DC); void zend_do_use_function(znode *name, znode *new_name, int is_global TSRMLS_DC); void zend_do_use_const(znode *name, znode *new_name, int is_global TSRMLS_DC); void zend_do_end_compilation(TSRMLS_D); From e14a769c56f45be26f32506483a7dff5b447fbb7 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Thu, 29 Aug 2013 17:15:36 +0200 Subject: [PATCH 15/26] Add test for conditional function declaration --- .../conditional_function_declaration.phpt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Zend/tests/use_function/conditional_function_declaration.phpt diff --git a/Zend/tests/use_function/conditional_function_declaration.phpt b/Zend/tests/use_function/conditional_function_declaration.phpt new file mode 100644 index 00000000000..ccfb96103a6 --- /dev/null +++ b/Zend/tests/use_function/conditional_function_declaration.phpt @@ -0,0 +1,17 @@ +--TEST-- +function that is conditionally defined at runtime should not cause compiler error +--FILE-- + +--EXPECT-- +Done From d7e3aca9c96e93acfee2deeeb7b481cadd28438d Mon Sep 17 00:00:00 2001 From: Anthony Ferrara Date: Fri, 30 Aug 2013 11:53:57 -0400 Subject: [PATCH 16/26] Fix issue with global fallback when not in global space --- .../use_function/no_global_fallback2.phpt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Zend/tests/use_function/no_global_fallback2.phpt diff --git a/Zend/tests/use_function/no_global_fallback2.phpt b/Zend/tests/use_function/no_global_fallback2.phpt new file mode 100644 index 00000000000..5d012c10e59 --- /dev/null +++ b/Zend/tests/use_function/no_global_fallback2.phpt @@ -0,0 +1,18 @@ +--TEST-- +non-existent imported functions should not be looked up in the global table +--FILE-- + +--EXPECTF-- +Fatal error: Call to undefined function bar\test() in %s on line %d From 612e77e5c9aabe6c3dc991732f3ccd9d80b6efbb Mon Sep 17 00:00:00 2001 From: Anthony Ferrara Date: Fri, 30 Aug 2013 11:55:43 -0400 Subject: [PATCH 17/26] Fix issue with global fallback not in global space --- Zend/zend_compile.c | 16 +++++++++------- Zend/zend_compile.h | 6 +++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 623fe15fed4..15dce18f7c2 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1962,7 +1962,7 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace char *lcname; char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant)); - zend_resolve_function_name(function_name, check_namespace TSRMLS_CC); + zend_resolve_function_name(function_name, &check_namespace TSRMLS_CC); if (check_namespace && CG(current_namespace) && !is_compound) { /* We assume we call function from the current namespace @@ -2101,7 +2101,7 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML } /* }}} */ -void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, zend_bool case_sensitive, HashTable *current_import_sub TSRMLS_DC) /* {{{ */ +void zend_resolve_non_class_name(znode *element_name, zend_bool *check_namespace, zend_bool case_sensitive, HashTable *current_import_sub TSRMLS_DC) /* {{{ */ { znode tmp; int len; @@ -2115,7 +2115,7 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, return; } - if(!check_namespace) { + if(!*check_namespace) { return; } @@ -2132,6 +2132,7 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, element_name->u.constant = **ns; zval_copy_ctor(&element_name->u.constant); efree(lookup_name); + *check_namespace = 0; return; } efree(lookup_name); @@ -2156,6 +2157,7 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, zend_do_build_namespace_name(&tmp, &tmp, element_name TSRMLS_CC); *element_name = tmp; efree(lookup_name); + *check_namespace = 0; return; } efree(lookup_name); @@ -2174,13 +2176,13 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, } /* }}} */ -void zend_resolve_function_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ +void zend_resolve_function_name(znode *element_name, zend_bool *check_namespace TSRMLS_DC) /* {{{ */ { zend_resolve_non_class_name(element_name, check_namespace, 0, CG(current_import_function) TSRMLS_CC); } /* }}} */ -void zend_resolve_const_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ +void zend_resolve_const_name(znode *element_name, zend_bool *check_namespace TSRMLS_DC) /* {{{ */ { zend_resolve_non_class_name(element_name, check_namespace, 1, CG(current_import_const) TSRMLS_CC); } @@ -5688,7 +5690,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con break; } - zend_resolve_const_name(constant_name, check_namespace TSRMLS_CC); + zend_resolve_const_name(constant_name, &check_namespace TSRMLS_CC); if(!compound) { fetch_type |= IS_CONSTANT_UNQUALIFIED; @@ -5700,7 +5702,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con case ZEND_RT: compound = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant)); - zend_resolve_const_name(constant_name, check_namespace TSRMLS_CC); + zend_resolve_const_name(constant_name, &check_namespace TSRMLS_CC); if(zend_constant_ct_subst(result, &constant_name->u.constant, 1 TSRMLS_CC)) { break; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index e8c0309319d..55575f39943 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -437,9 +437,9 @@ ZEND_API char *zend_get_compiled_filename(TSRMLS_D); ZEND_API int zend_get_compiled_lineno(TSRMLS_D); ZEND_API size_t zend_get_scanned_file_offset(TSRMLS_D); -void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace, zend_bool case_sensitive, HashTable *current_import_sub TSRMLS_DC); -void zend_resolve_function_name(znode *element_name, zend_bool check_namespace TSRMLS_DC); -void zend_resolve_const_name(znode *element_name, zend_bool check_namespace TSRMLS_DC); +void zend_resolve_non_class_name(znode *element_name, zend_bool *check_namespace, zend_bool case_sensitive, HashTable *current_import_sub TSRMLS_DC); +void zend_resolve_function_name(znode *element_name, zend_bool *check_namespace TSRMLS_DC); +void zend_resolve_const_name(znode *element_name, zend_bool *check_namespace TSRMLS_DC); void zend_resolve_class_name(znode *class_name, ulong fetch_type, int check_ns_name TSRMLS_DC); ZEND_API const char* zend_get_compiled_variable_name(const zend_op_array *op_array, zend_uint var, int* name_len); From 98e4ecb6f042feb308d27130b9b48ab90729f049 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Thu, 19 Sep 2013 10:51:57 +0200 Subject: [PATCH 18/26] fix Zend/tests/ns_040.phpt failing It was wrongly assumed the namespace has to be looked up in a case sensitive manner too. Fixed the lookup to use a lower case represenation of the import name. --- Zend/zend_compile.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 15dce18f7c2..b811554812d 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2140,11 +2140,8 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool *check_namespace if (compound && CG(current_import)) { len = compound - Z_STRVAL(element_name->u.constant); - if (case_sensitive) { - lookup_name = estrndup(Z_STRVAL(element_name->u.constant), len); - } else { - lookup_name = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); - } + /* namespace is always lowercase */ + lookup_name = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); /* Check if first part of compound name is an import name */ if (zend_hash_find(CG(current_import), lookup_name, len+1, (void**)&ns) == SUCCESS) { /* Substitute import name */ From e23ad4eeb2249c18f11eee751611395cb845c010 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Mon, 14 Oct 2013 23:21:06 +0200 Subject: [PATCH 19/26] Add "Done" output to distinguish hard from soft failures --- Zend/tests/use_const/define_imported_before.phpt | 4 ++++ Zend/tests/use_function/define_imported_before.phpt | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Zend/tests/use_const/define_imported_before.phpt b/Zend/tests/use_const/define_imported_before.phpt index 19374a2c586..f674ce81e8e 100644 --- a/Zend/tests/use_const/define_imported_before.phpt +++ b/Zend/tests/use_const/define_imported_before.phpt @@ -9,6 +9,10 @@ namespace { use const foo\bar; } +namespace { + echo "Done"; +} + ?> --EXPECTF-- Fatal error: Cannot use const foo\bar as bar because the name is already in use in %s on line %d diff --git a/Zend/tests/use_function/define_imported_before.phpt b/Zend/tests/use_function/define_imported_before.phpt index ff5d5ca28d3..91974e0783d 100644 --- a/Zend/tests/use_function/define_imported_before.phpt +++ b/Zend/tests/use_function/define_imported_before.phpt @@ -9,6 +9,10 @@ namespace { use function foo\bar; } +namespace { + echo "Done"; +} + ?> --EXPECTF-- Fatal error: Cannot use function foo\bar as bar because the name is already in use in %s on line %d From 602fef0e52caacf754eacfb96e9342ce32d29a37 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Mon, 14 Oct 2013 23:32:11 +0200 Subject: [PATCH 20/26] Clarify type of use in error messages --- Zend/tests/use_const/conflicting_use.phpt | 2 +- Zend/tests/use_function/case_insensivity.phpt | 2 +- Zend/tests/use_function/conflicting_use.phpt | 2 +- Zend/zend_compile.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Zend/tests/use_const/conflicting_use.phpt b/Zend/tests/use_const/conflicting_use.phpt index f873fdcc653..3b3c4b3262e 100644 --- a/Zend/tests/use_const/conflicting_use.phpt +++ b/Zend/tests/use_const/conflicting_use.phpt @@ -18,4 +18,4 @@ namespace { ?> --EXPECTF-- -Fatal error: Cannot use bar\baz as baz because the name is already in use in %s on line %d +Fatal error: Cannot use const bar\baz as baz because the name is already in use in %s on line %d diff --git a/Zend/tests/use_function/case_insensivity.phpt b/Zend/tests/use_function/case_insensivity.phpt index 53ae3658a97..ba6e3a7e4b1 100644 --- a/Zend/tests/use_function/case_insensivity.phpt +++ b/Zend/tests/use_function/case_insensivity.phpt @@ -10,4 +10,4 @@ namespace { ?> --EXPECTF-- -Fatal error: Cannot use foo\BAR as BAR because the name is already in use in %s on line %d +Fatal error: Cannot use function foo\BAR as BAR because the name is already in use in %s on line %d diff --git a/Zend/tests/use_function/conflicting_use.phpt b/Zend/tests/use_function/conflicting_use.phpt index ed531e4febe..0221fbdebb3 100644 --- a/Zend/tests/use_function/conflicting_use.phpt +++ b/Zend/tests/use_function/conflicting_use.phpt @@ -22,4 +22,4 @@ namespace { ?> --EXPECTF-- -Fatal error: Cannot use bar\baz as baz because the name is already in use in %s on line %d +Fatal error: Cannot use function bar\baz as baz because the name is already in use in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index b811554812d..9c238ac67cf 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7220,10 +7220,10 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const } if (zend_hash_add(current_import_sub, lookup_name, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { - zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name)); + zend_error(E_COMPILE_ERROR, "Cannot use %s %s as %s because the name is already in use", type, Z_STRVAL_P(ns), Z_STRVAL_P(name)); } if (warn) { - zend_error(E_WARNING, "The use statement with non-compound name '%s' has no effect", Z_STRVAL_P(name)); + zend_error(E_WARNING, "The use %s statement with non-compound name '%s' has no effect", type, Z_STRVAL_P(name)); } efree(lookup_name); zval_dtor(name); From 9711c58bc4236c0e2e482af9b20581e78af0c7ca Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Fri, 8 Nov 2013 20:26:46 -0500 Subject: [PATCH 21/26] Stop PHP from modifying the lowercase function name in place. --- Zend/zend_compile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 9c238ac67cf..03136637356 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1740,13 +1740,14 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC); Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))); opline->op2_type = IS_CONST; - LITERAL_STRINGL(opline->op2, lcname, name_len, 0); + LITERAL_STRINGL(opline->op2, lcname, name_len, 1); CALCULATE_LITERAL_HASH(opline->op2.constant); opline->extended_value = ZEND_DECLARE_FUNCTION; zend_hash_quick_update(CG(function_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); zend_hash_add(&CG(function_filenames), lcname, strlen(lcname)+1, CG(compiled_filename), strlen(CG(compiled_filename))+1, NULL); zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context))); zend_init_compiler_context(TSRMLS_C); + str_efree(lcname); } if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) { From 1ea01f55dbfbefd3b351f05c405e85ac778cdee7 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Fri, 8 Nov 2013 21:29:23 -0500 Subject: [PATCH 22/26] Look in the function_table instead of function_filenames for actually declared functions. --- Zend/zend_compile.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 03136637356..228fe6f87de 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7163,7 +7163,7 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const char *type, zend_bool case_sensitive, HashTable *current_import_sub, HashTable *lookup_table TSRMLS_DC) /* {{{ */ { char *lookup_name; - char *filename; + zend_function *function = NULL; zval *name, *ns, tmp; zend_bool warn = 0; @@ -7210,14 +7210,16 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const efree(tmp2); } efree(c_ns_name); - } else if (zend_hash_find(lookup_table, lookup_name, Z_STRLEN_P(name)+1, (void **)&filename) == SUCCESS && strcmp(filename, CG(compiled_filename)) == 0) { - char *c_tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); + } else { + if (zend_hash_find(lookup_table, lookup_name, Z_STRLEN_P(name)+1, (void **) &function) == SUCCESS && strcmp(function->op_array.filename, CG(compiled_filename)) == 0) { + char *c_tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); - if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) || - memcmp(c_tmp, lookup_name, Z_STRLEN_P(ns))) { - zend_error(E_COMPILE_ERROR, "Cannot use %s %s as %s because the name is already in use", type, Z_STRVAL_P(ns), Z_STRVAL_P(name)); + if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) || + memcmp(c_tmp, lookup_name, Z_STRLEN_P(ns))) { + zend_error(E_COMPILE_ERROR, "Cannot use %s %s as %s because the name is already in use", type, Z_STRVAL_P(ns), Z_STRVAL_P(name)); + } + efree(c_tmp); } - efree(c_tmp); } if (zend_hash_add(current_import_sub, lookup_name, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { @@ -7238,7 +7240,7 @@ void zend_do_use_function(znode *ns_name, znode *new_name, int is_global TSRMLS_ zend_hash_init(CG(current_import_function), 0, NULL, ZVAL_PTR_DTOR, 0); } - zend_do_use_non_class(ns_name, new_name, is_global, "function", 0, CG(current_import_function), &CG(function_filenames) TSRMLS_CC); + zend_do_use_non_class(ns_name, new_name, is_global, "function", 0, CG(current_import_function), CG(function_table) TSRMLS_CC); } /* }}} */ From 95675dfba9e417667e1e093084b27fd8f93d8724 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Fri, 8 Nov 2013 21:32:09 -0500 Subject: [PATCH 23/26] Remove now unused function_filenames struct. --- Zend/zend_compile.c | 3 --- Zend/zend_globals.h | 1 - 2 files changed, 4 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 228fe6f87de..bd90477efdc 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -206,7 +206,6 @@ void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */ CG(current_import) = NULL; CG(current_import_function) = NULL; CG(current_import_const) = NULL; - zend_hash_init(&CG(function_filenames), 0, NULL, NULL, 0); zend_hash_init(&CG(const_filenames), 0, NULL, NULL, 0); init_compiler_declarables(TSRMLS_C); zend_stack_init(&CG(context_stack)); @@ -246,7 +245,6 @@ void shutdown_compiler(TSRMLS_D) /* {{{ */ zend_stack_destroy(&CG(list_stack)); zend_hash_destroy(&CG(filenames_table)); zend_llist_destroy(&CG(open_files)); - zend_hash_destroy(&CG(function_filenames)); zend_hash_destroy(&CG(const_filenames)); zend_stack_destroy(&CG(context_stack)); } @@ -1744,7 +1742,6 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n CALCULATE_LITERAL_HASH(opline->op2.constant); opline->extended_value = ZEND_DECLARE_FUNCTION; zend_hash_quick_update(CG(function_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); - zend_hash_add(&CG(function_filenames), lcname, strlen(lcname)+1, CG(compiled_filename), strlen(CG(compiled_filename))+1, NULL); zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context))); zend_init_compiler_context(TSRMLS_C); str_efree(lcname); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 19c29c68f32..27d471fa069 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -136,7 +136,6 @@ struct _zend_compiler_globals { zend_bool in_namespace; zend_bool has_bracketed_namespaces; - HashTable function_filenames; HashTable const_filenames; zend_compiler_context context; From da553a816653e7c19bbfb5454fced91b929a6075 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Fri, 8 Nov 2013 21:37:38 -0500 Subject: [PATCH 24/26] Fix constant resolution. --- Zend/zend_compile.c | 31 ++++++++++++++++++++++--------- Zend/zend_compile.h | 2 +- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index bd90477efdc..96fb77a29be 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7157,10 +7157,9 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ } /* }}} */ -void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const char *type, zend_bool case_sensitive, HashTable *current_import_sub, HashTable *lookup_table TSRMLS_DC) /* {{{ */ +void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, int is_function, zend_bool case_sensitive, HashTable *current_import_sub, HashTable *lookup_table TSRMLS_DC) /* {{{ */ { char *lookup_name; - zend_function *function = NULL; zval *name, *ns, tmp; zend_bool warn = 0; @@ -7202,28 +7201,42 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const if (Z_STRLEN_P(ns) != Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) || memcmp(tmp2, c_ns_name, Z_STRLEN_P(ns))) { - zend_error(E_COMPILE_ERROR, "Cannot use %s %s as %s because the name is already in use", type, Z_STRVAL_P(ns), Z_STRVAL_P(name)); + zend_error(E_COMPILE_ERROR, "Cannot use %s %s as %s because the name is already in use", is_function ? "function" : "const", Z_STRVAL_P(ns), Z_STRVAL_P(name)); } efree(tmp2); } efree(c_ns_name); - } else { + } else if (is_function) { + zend_function *function; + if (zend_hash_find(lookup_table, lookup_name, Z_STRLEN_P(name)+1, (void **) &function) == SUCCESS && strcmp(function->op_array.filename, CG(compiled_filename)) == 0) { char *c_tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) || memcmp(c_tmp, lookup_name, Z_STRLEN_P(ns))) { - zend_error(E_COMPILE_ERROR, "Cannot use %s %s as %s because the name is already in use", type, Z_STRVAL_P(ns), Z_STRVAL_P(name)); + zend_error(E_COMPILE_ERROR, "Cannot use function %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name)); + } + efree(c_tmp); + } + } else { + const char *filename; + + if (zend_hash_find(lookup_table, lookup_name, Z_STRLEN_P(name)+1, (void **) &filename) == SUCCESS && strcmp(filename, CG(compiled_filename)) == 0) { + char *c_tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); + + if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) || + memcmp(c_tmp, lookup_name, Z_STRLEN_P(ns))) { + zend_error(E_COMPILE_ERROR, "Cannot use const %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name)); } efree(c_tmp); } } if (zend_hash_add(current_import_sub, lookup_name, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { - zend_error(E_COMPILE_ERROR, "Cannot use %s %s as %s because the name is already in use", type, Z_STRVAL_P(ns), Z_STRVAL_P(name)); + zend_error(E_COMPILE_ERROR, "Cannot use %s %s as %s because the name is already in use", is_function ? "function" : "const", Z_STRVAL_P(ns), Z_STRVAL_P(name)); } if (warn) { - zend_error(E_WARNING, "The use %s statement with non-compound name '%s' has no effect", type, Z_STRVAL_P(name)); + zend_error(E_WARNING, "The use %s statement with non-compound name '%s' has no effect", is_function ? "function" : "const", Z_STRVAL_P(name)); } efree(lookup_name); zval_dtor(name); @@ -7237,7 +7250,7 @@ void zend_do_use_function(znode *ns_name, znode *new_name, int is_global TSRMLS_ zend_hash_init(CG(current_import_function), 0, NULL, ZVAL_PTR_DTOR, 0); } - zend_do_use_non_class(ns_name, new_name, is_global, "function", 0, CG(current_import_function), CG(function_table) TSRMLS_CC); + zend_do_use_non_class(ns_name, new_name, is_global, 1, 0, CG(current_import_function), CG(function_table) TSRMLS_CC); } /* }}} */ @@ -7248,7 +7261,7 @@ void zend_do_use_const(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) zend_hash_init(CG(current_import_const), 0, NULL, ZVAL_PTR_DTOR, 0); } - zend_do_use_non_class(ns_name, new_name, is_global, "const", 1, CG(current_import_const), &CG(const_filenames) TSRMLS_CC); + zend_do_use_non_class(ns_name, new_name, is_global, 0, 1, CG(current_import_const), &CG(const_filenames) TSRMLS_CC); } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 55575f39943..53bff384702 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -638,7 +638,7 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_brackets TSRMLS_D void zend_do_end_namespace(TSRMLS_D); void zend_verify_namespace(TSRMLS_D); void zend_do_use(znode *name, znode *new_name, int is_global TSRMLS_DC); -void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, const char *type, zend_bool case_sensitive, HashTable *current_import_sub, HashTable *lookup_table TSRMLS_DC); +void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, int is_function, zend_bool case_sensitive, HashTable *current_import_sub, HashTable *lookup_table TSRMLS_DC); void zend_do_use_function(znode *name, znode *new_name, int is_global TSRMLS_DC); void zend_do_use_const(znode *name, znode *new_name, int is_global TSRMLS_DC); void zend_do_end_compilation(TSRMLS_D); From cc049e64500ed0f6efd9e6827e4bda1b23368c61 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Fri, 8 Nov 2013 21:49:05 -0500 Subject: [PATCH 25/26] Only check user functions for filenames. --- Zend/zend_compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 96fb77a29be..14a28f392be 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7209,7 +7209,7 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, int i } else if (is_function) { zend_function *function; - if (zend_hash_find(lookup_table, lookup_name, Z_STRLEN_P(name)+1, (void **) &function) == SUCCESS && strcmp(function->op_array.filename, CG(compiled_filename)) == 0) { + if (zend_hash_find(lookup_table, lookup_name, Z_STRLEN_P(name)+1, (void **) &function) == SUCCESS && function->type == ZEND_USER_FUNCTION && strcmp(function->op_array.filename, CG(compiled_filename)) == 0) { char *c_tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) || From 611da37617749c81ab22b1e44a0cc1f294cc493a Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sat, 9 Nov 2013 13:48:23 -0500 Subject: [PATCH 26/26] use ZVAL_ZVAL to init ZVAL from ZVAL --- Zend/zend_compile.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 3bee7451719..44e95adf86c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7055,7 +7055,7 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ } ALLOC_ZVAL(ns); - *ns = ns_name->u.constant; + ZVAL_ZVAL(ns, &ns_name->u.constant, 0, 0); if (new_name) { name = &new_name->u.constant; } else { @@ -7068,8 +7068,7 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ if (p) { ZVAL_STRING(name, p+1, 1); } else { - *name = *ns; - zval_copy_ctor(name); + ZVAL_ZVAL(name, ns, 1, 0); warn = !is_global && !CG(current_namespace); } } @@ -7133,7 +7132,7 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, int i zend_bool warn = 0; ALLOC_ZVAL(ns); - *ns = ns_name->u.constant; + ZVAL_ZVAL(ns, &ns_name->u.constant, 0, 0); if (new_name) { name = &new_name->u.constant; } else { @@ -7146,8 +7145,7 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, int i if (p) { ZVAL_STRING(name, p+1, 1); } else { - *name = *ns; - zval_copy_ctor(name); + ZVAL_ZVAL(name, ns, 1, 0); warn = !is_global && !CG(current_namespace); } }