Created
December 20, 2014 10:09
-
-
Save dstogov/3956efd7bbf924cfa0f8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c | |
index c05e797..f956f49 100644 | |
--- a/Zend/zend_builtin_functions.c | |
+++ b/Zend/zend_builtin_functions.c | |
@@ -688,6 +688,71 @@ ZEND_FUNCTION(error_reporting) | |
} | |
/* }}} */ | |
+static int validate_constant_array(HashTable *ht) /* {{{ */ | |
+{ | |
+ int ret = 1; | |
+ zval *val; | |
+ | |
+ ht->u.v.nApplyCount++; | |
+ ZEND_HASH_FOREACH_VAL_IND(ht, val) { | |
+ ZVAL_DEREF(val); | |
+ if (Z_REFCOUNTED_P(val)) { | |
+ if (Z_TYPE_P(val) == IS_ARRAY) { | |
+ if (!Z_IMMUTABLE_P(val)) { | |
+ if (Z_ARRVAL_P(val)->u.v.nApplyCount > 0) { | |
+ zend_error(E_WARNING, "Constants cannot be recursive arrays"); | |
+ ret = 0; | |
+ break; | |
+ } else if (!validate_constant_array(Z_ARRVAL_P(val))) { | |
+ ret = 0; | |
+ break; | |
+ } | |
+ } | |
+ } else if (Z_TYPE_P(val) != IS_STRING && Z_TYPE_P(val) != IS_RESOURCE) { | |
+ zend_error(E_WARNING, "Constants may only evaluate to scalar values or arrays"); | |
+ ret = 0; | |
+ break; | |
+ } | |
+ } | |
+ } ZEND_HASH_FOREACH_END(); | |
+ ht->u.v.nApplyCount--; | |
+ return ret; | |
+} | |
+/* }}} */ | |
+ | |
+static void copy_constant_array(zval *dst, zval *src) /* {{{ */ | |
+{ | |
+ zend_string *key; | |
+ zend_ulong idx; | |
+ zval *new_val, *val; | |
+ | |
+ array_init_size(dst, zend_hash_num_elements(Z_ARRVAL_P(src))); | |
+ ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(src), idx, key, val) { | |
+ /* constant arrays can't contain references */ | |
+ if (Z_ISREF_P(val)) { | |
+ if (Z_REFCOUNT_P(val) == 1) { | |
+ ZVAL_UNREF(val); | |
+ } else { | |
+ Z_DELREF_P(val); | |
+ val = Z_REFVAL_P(val); | |
+ } | |
+ } | |
+ if (key) { | |
+ new_val = zend_hash_add_new(Z_ARRVAL_P(dst), key, val); | |
+ } else { | |
+ new_val = zend_hash_index_add_new(Z_ARRVAL_P(dst), idx, val); | |
+ } | |
+ if (Z_TYPE_P(val) == IS_ARRAY) { | |
+ if (!Z_IMMUTABLE_P(val)) { | |
+ copy_constant_array(new_val, val); | |
+ } | |
+ } else if (Z_REFCOUNTED_P(val)) { | |
+ Z_ADDREF_P(val); | |
+ } | |
+ } ZEND_HASH_FOREACH_END(); | |
+} | |
+/* }}} */ | |
+ | |
/* {{{ proto bool define(string constant_name, mixed value, boolean case_insensitive=false) | |
Define a new constant */ | |
ZEND_FUNCTION(define) | |
@@ -733,6 +798,16 @@ repeat: | |
case IS_RESOURCE: | |
case IS_NULL: | |
break; | |
+ case IS_ARRAY: | |
+ if (!Z_IMMUTABLE_P(val)) { | |
+ if (!validate_constant_array(Z_ARRVAL_P(val))) { | |
+ RETURN_FALSE; | |
+ } else { | |
+ copy_constant_array(&c.value, val); | |
+ goto register_constant; | |
+ } | |
+ } | |
+ break; | |
case IS_OBJECT: | |
if (Z_TYPE(val_free) == IS_UNDEF) { | |
if (Z_OBJ_HT_P(val)->get) { | |
@@ -749,13 +824,14 @@ repeat: | |
} | |
/* no break */ | |
default: | |
- zend_error(E_WARNING,"Constants may only evaluate to scalar values"); | |
+ zend_error(E_WARNING, "Constants may only evaluate to scalar values or arrays"); | |
zval_ptr_dtor(&val_free); | |
RETURN_FALSE; | |
} | |
ZVAL_DUP(&c.value, val); | |
zval_ptr_dtor(&val_free); | |
+register_constant: | |
c.flags = case_sensitive; /* non persistent */ | |
c.name = zend_string_copy(name); | |
c.module_number = PHP_USER_CONSTANT; | |
diff --git a/Zend/tests/constant_arrays.phpt b/Zend/tests/constant_arrays.phpt | |
new file mode 100644 | |
index 0000000..834c126 | |
--- /dev/null | |
+++ b/Zend/tests/constant_arrays.phpt | |
@@ -0,0 +1,99 @@ | |
+--TEST-- | |
+Constant arrays | |
+--FILE-- | |
+<?php | |
+ | |
+define('FOOBAR', [1, 2, 3, ['foo' => 'bar']]); | |
+const FOO_BAR = [1, 2, 3, ['foo' => 'bar']]; | |
+ | |
+$x = FOOBAR; | |
+$x[0] = 7; | |
+var_dump($x, FOOBAR); | |
+ | |
+$x = FOO_BAR; | |
+$x[0] = 7; | |
+var_dump($x, FOO_BAR); | |
+ | |
+// ensure references are removed | |
+$x = 7; | |
+$y = [&$x]; | |
+define('QUX', $y); | |
+$y[0] = 3; | |
+var_dump($x, $y, QUX); | |
+ | |
+// ensure objects not allowed in arrays | |
+var_dump(define('ELEPHPANT', [new StdClass])); | |
+ | |
+// ensure recursion doesn't crash | |
+$recursive = []; | |
+$recursive[0] = &$recursive; | |
+var_dump(define('RECURSION', $recursive)); | |
+ | |
+--EXPECTF-- | |
+array(4) { | |
+ [0]=> | |
+ int(7) | |
+ [1]=> | |
+ int(2) | |
+ [2]=> | |
+ int(3) | |
+ [3]=> | |
+ array(1) { | |
+ ["foo"]=> | |
+ string(3) "bar" | |
+ } | |
+} | |
+array(4) { | |
+ [0]=> | |
+ int(1) | |
+ [1]=> | |
+ int(2) | |
+ [2]=> | |
+ int(3) | |
+ [3]=> | |
+ array(1) { | |
+ ["foo"]=> | |
+ string(3) "bar" | |
+ } | |
+} | |
+array(4) { | |
+ [0]=> | |
+ int(7) | |
+ [1]=> | |
+ int(2) | |
+ [2]=> | |
+ int(3) | |
+ [3]=> | |
+ array(1) { | |
+ ["foo"]=> | |
+ string(3) "bar" | |
+ } | |
+} | |
+array(4) { | |
+ [0]=> | |
+ int(1) | |
+ [1]=> | |
+ int(2) | |
+ [2]=> | |
+ int(3) | |
+ [3]=> | |
+ array(1) { | |
+ ["foo"]=> | |
+ string(3) "bar" | |
+ } | |
+} | |
+int(3) | |
+array(1) { | |
+ [0]=> | |
+ int(3) | |
+} | |
+array(1) { | |
+ [0]=> | |
+ int(7) | |
+} | |
+ | |
+Warning: Constants may only evaluate to scalar values or arrays in %s on line %d | |
+bool(false) | |
+ | |
+Warning: Constants cannot be recursive arrays in %s on line %d | |
+bool(false) | |
diff --git a/Zend/tests/008.phpt b/Zend/tests/008.phpt | |
index 4f58e80..3e990fb 100644 | |
--- a/Zend/tests/008.phpt | |
+++ b/Zend/tests/008.phpt | |
@@ -41,11 +41,9 @@ bool(true) | |
Notice: Constant test const already defined in %s on line %d | |
bool(false) | |
+bool(true) | |
-Warning: Constants may only evaluate to scalar values in %s on line %d | |
-bool(false) | |
- | |
-Warning: Constants may only evaluate to scalar values in %s on line %d | |
+Warning: Constants may only evaluate to scalar values or arrays in %s on line %d | |
bool(false) | |
int(1) | |
int(2) | |
diff --git a/Zend/tests/bug37811.phpt b/Zend/tests/bug37811.phpt | |
index 70c4c90..f224f9b 100644 | |
--- a/Zend/tests/bug37811.phpt | |
+++ b/Zend/tests/bug37811.phpt | |
@@ -21,7 +21,7 @@ var_dump(Baz); | |
--EXPECTF-- | |
string(3) "Foo" | |
-Warning: Constants may only evaluate to scalar values in %sbug37811.php on line %d | |
+Warning: Constants may only evaluate to scalar values or arrays in %sbug37811.php on line %d | |
Notice: Use of undefined constant Baz - assumed 'Baz' in %sbug37811.php on line %d | |
string(3) "Baz" | |
diff --git a/Zend/tests/constants_002.phpt b/Zend/tests/constants_002.phpt | |
index 5acca98..d590bf4 100644 | |
--- a/Zend/tests/constants_002.phpt | |
+++ b/Zend/tests/constants_002.phpt | |
@@ -11,7 +11,7 @@ var_dump(foo); | |
?> | |
--EXPECTF-- | |
-Warning: Constants may only evaluate to scalar values in %s on line %d | |
+Warning: Constants may only evaluate to scalar values or arrays in %s on line %d | |
Notice: Use of undefined constant foo - assumed 'foo' in %s on line %d | |
string(%d) "foo" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment