Skip to content

Commit 85d4cfb

Browse files
committed
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
1 parent 30f16c3 commit 85d4cfb

17 files changed

+99
-59
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
namespace foo;
4+
5+
const bar = 'local bar';
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
namespace foo;
4+
5+
const PHP_VERSION = 42;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php
2+
3+
const bar = 'global bar';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php
2+
3+
const baz = NULL;

Zend/tests/use_const/no_global_fallback.phpt

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,10 @@ non-existent imported constants should not be looked up in the global table
33
--FILE--
44
<?php
55

6-
namespace {
7-
const baz = NULL;
8-
}
6+
require 'includes/global_baz.php';
97

10-
namespace {
11-
use const foo\bar\baz;
12-
var_dump(baz);
13-
}
8+
use const foo\bar\baz;
9+
var_dump(baz);
1410

1511
?>
1612
--EXPECTF--

Zend/tests/use_const/shadow_core.phpt

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,14 @@ shadowing a global core constant with a local version
33
--FILE--
44
<?php
55

6-
namespace foo {
7-
const PHP_VERSION = 42;
8-
}
6+
require 'includes/foo_php_version.php';
97

10-
namespace {
11-
var_dump(PHP_VERSION);
12-
}
8+
use const foo\PHP_VERSION;
139

14-
namespace {
15-
use const foo\PHP_VERSION;
16-
var_dump(PHP_VERSION);
17-
echo "Done\n";
18-
}
10+
var_dump(PHP_VERSION);
11+
echo "Done\n";
1912

2013
?>
2114
--EXPECTF--
22-
string(%d) "%s"
2315
int(42)
2416
Done

Zend/tests/use_const/shadow_global.phpt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@ shadowing a global constant with a local version
44
<?php
55

66
namespace {
7-
const bar = 'global bar';
8-
}
9-
10-
namespace foo {
11-
const bar = 'local bar';
7+
require 'includes/global_bar.php';
8+
require 'includes/foo_bar.php';
129
}
1310

1411
namespace {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace foo;
4+
5+
function bar() {
6+
return 'local bar';
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace foo;
4+
5+
function strlen($str) {
6+
return 4;
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
function bar() {
4+
return 'global bar';
5+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
3+
function baz() {
4+
}

Zend/tests/use_function/no_global_fallback.phpt

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,10 @@ non-existent imported functions should not be looked up in the global table
33
--FILE--
44
<?php
55

6-
namespace {
7-
function baz() {
8-
}
9-
}
6+
require 'includes/global_baz.php';
107

11-
namespace {
12-
use function foo\bar\baz;
13-
var_dump(baz());
14-
}
8+
use function foo\bar\baz;
9+
var_dump(baz());
1510

1611
?>
1712
--EXPECTF--

Zend/tests/use_function/shadow_core.phpt

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,14 @@ shadowing a global core function with a local version
33
--FILE--
44
<?php
55

6-
namespace foo {
7-
function strlen($str) {
8-
return 4;
9-
}
10-
}
6+
require 'includes/foo_strlen.php';
117

12-
namespace {
13-
var_dump(strlen('foo bar baz'));
14-
}
8+
use function foo\strlen;
159

16-
namespace {
17-
use function foo\strlen;
18-
var_dump(strlen('foo bar baz'));
19-
echo "Done\n";
20-
}
10+
var_dump(strlen('foo bar baz'));
11+
echo "Done\n";
2112

2213
?>
2314
--EXPECT--
24-
int(11)
2515
int(4)
2616
Done

Zend/tests/use_function/shadow_global.phpt

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,8 @@ shadowing a global function with a local version
44
<?php
55

66
namespace {
7-
function bar() {
8-
return 'global bar';
9-
}
10-
}
11-
12-
namespace foo {
13-
function bar() {
14-
return 'local bar';
15-
}
7+
require 'includes/global_bar.php';
8+
require 'includes/foo_bar.php';
169
}
1710

1811
namespace {

Zend/zend_compile.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */
206206
CG(current_import) = NULL;
207207
CG(current_import_function) = NULL;
208208
CG(current_import_const) = NULL;
209+
zend_hash_init(&CG(function_filenames), 0, NULL, NULL, 0);
210+
zend_hash_init(&CG(const_filenames), 0, NULL, NULL, 0);
209211
init_compiler_declarables(TSRMLS_C);
210212
zend_stack_init(&CG(context_stack));
211213

@@ -244,6 +246,8 @@ void shutdown_compiler(TSRMLS_D) /* {{{ */
244246
zend_stack_destroy(&CG(list_stack));
245247
zend_hash_destroy(&CG(filenames_table));
246248
zend_llist_destroy(&CG(open_files));
249+
zend_hash_destroy(&CG(function_filenames));
250+
zend_hash_destroy(&CG(const_filenames));
247251
zend_stack_destroy(&CG(context_stack));
248252
}
249253
/* }}} */
@@ -1740,6 +1744,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
17401744
CALCULATE_LITERAL_HASH(opline->op2.constant);
17411745
opline->extended_value = ZEND_DECLARE_FUNCTION;
17421746
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));
1747+
zend_hash_add(&CG(function_filenames), lcname, strlen(lcname)+1, CG(compiled_filename), strlen(CG(compiled_filename))+1, NULL);
17431748
zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context)));
17441749
zend_init_compiler_context(TSRMLS_C);
17451750
}
@@ -7147,9 +7152,10 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{
71477152
}
71487153
/* }}} */
71497154

7150-
void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, HashTable *current_import_sub TSRMLS_DC) /* {{{ */
7155+
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) /* {{{ */
71517156
{
71527157
char *lcname;
7158+
char *filename;
71537159
zval *name, *ns, tmp;
71547160
zend_bool warn = 0;
71557161

@@ -7182,6 +7188,33 @@ void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, HashT
71827188
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));
71837189
}
71847190

7191+
if (CG(current_namespace)) {
7192+
/* Prefix import name with current namespace name to avoid conflicts with classes */
7193+
char *c_ns_name = emalloc(Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) + 1);
7194+
7195+
zend_str_tolower_copy(c_ns_name, Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace)));
7196+
c_ns_name[Z_STRLEN_P(CG(current_namespace))] = '\\';
7197+
memcpy(c_ns_name+Z_STRLEN_P(CG(current_namespace))+1, lcname, Z_STRLEN_P(name)+1);
7198+
if (zend_hash_exists(lookup_table, c_ns_name, Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name)+1)) {
7199+
char *tmp2 = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns));
7200+
7201+
if (Z_STRLEN_P(ns) != Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) ||
7202+
memcmp(tmp2, c_ns_name, Z_STRLEN_P(ns))) {
7203+
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));
7204+
}
7205+
efree(tmp2);
7206+
}
7207+
efree(c_ns_name);
7208+
} else if (zend_hash_find(lookup_table, lcname, Z_STRLEN_P(name)+1, (void **)&filename) == SUCCESS && strcmp(filename, CG(compiled_filename)) == 0) {
7209+
char *c_tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns));
7210+
7211+
if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) ||
7212+
memcmp(c_tmp, lcname, Z_STRLEN_P(ns))) {
7213+
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));
7214+
}
7215+
efree(c_tmp);
7216+
}
7217+
71857218
if (zend_hash_add(current_import_sub, lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) {
71867219
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));
71877220
}
@@ -7200,7 +7233,7 @@ void zend_do_use_function(znode *ns_name, znode *new_name, int is_global TSRMLS_
72007233
zend_hash_init(CG(current_import_function), 0, NULL, ZVAL_PTR_DTOR, 0);
72017234
}
72027235

7203-
zend_do_use_non_class(ns_name, new_name, is_global, CG(current_import_function) TSRMLS_CC);
7236+
zend_do_use_non_class(ns_name, new_name, is_global, "function", CG(current_import_function), &CG(function_filenames) TSRMLS_CC);
72047237
}
72057238
/* }}} */
72067239

@@ -7211,7 +7244,7 @@ void zend_do_use_const(znode *ns_name, znode *new_name, int is_global TSRMLS_DC)
72117244
zend_hash_init(CG(current_import_const), 0, NULL, ZVAL_PTR_DTOR, 0);
72127245
}
72137246

7214-
zend_do_use_non_class(ns_name, new_name, is_global, CG(current_import_const) TSRMLS_CC);
7247+
zend_do_use_non_class(ns_name, new_name, is_global, "const", CG(current_import_const), &CG(const_filenames) TSRMLS_CC);
72157248
}
72167249
/* }}} */
72177250

@@ -7243,6 +7276,8 @@ void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */
72437276
SET_UNUSED(opline->result);
72447277
SET_NODE(opline->op1, name);
72457278
SET_NODE(opline->op2, value);
7279+
7280+
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);
72467281
}
72477282
/* }}} */
72487283

Zend/zend_compile.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_brackets TSRMLS_D
638638
void zend_do_end_namespace(TSRMLS_D);
639639
void zend_verify_namespace(TSRMLS_D);
640640
void zend_do_use(znode *name, znode *new_name, int is_global TSRMLS_DC);
641-
void zend_do_use_non_class(znode *ns_name, znode *new_name, int is_global, HashTable *current_import_sub TSRMLS_DC);
641+
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);
642642
void zend_do_use_function(znode *name, znode *new_name, int is_global TSRMLS_DC);
643643
void zend_do_use_const(znode *name, znode *new_name, int is_global TSRMLS_DC);
644644
void zend_do_end_compilation(TSRMLS_D);

Zend/zend_globals.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ struct _zend_compiler_globals {
136136
zend_bool in_namespace;
137137
zend_bool has_bracketed_namespaces;
138138

139+
HashTable function_filenames;
140+
HashTable const_filenames;
141+
139142
zend_compiler_context context;
140143
zend_stack context_stack;
141144

0 commit comments

Comments
 (0)