summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Watkins <krakjoe@php.net>2016-03-31 12:40:15 +0100
committerJoe Watkins <krakjoe@php.net>2016-03-31 12:40:15 +0100
commit3b13206aa9d494af2cf4bde4047250405d5bbfd2 (patch)
treecbc4eee151d771cfb789fd8095023bd490c9fd41
parent233115ea236fd1aa258e8b733d3855d1261fba8b (diff)
parente6bb7eb3aa4b0be66130b8299a21e94eeeec2368 (diff)
downloadphp-git-3b13206aa9d494af2cf4bde4047250405d5bbfd2.tar.gz
Merge branch 'PHP-7.0' of https://github.com/php/php-src into PHP-7.0
-rw-r--r--NEWS10
-rw-r--r--Zend/tests/closure_invoke_case_insensitive.phpt16
-rw-r--r--Zend/zend_closures.c8
-rw-r--r--ext/fileinfo/libmagic/funcs.c2
-rw-r--r--ext/fileinfo/tests/bug68996.phpt7
-rw-r--r--ext/shmop/shmop.c1
-rw-r--r--ext/shmop/tests/003.phpt33
-rw-r--r--ext/spl/spl_array.c45
-rw-r--r--ext/standard/array.c33
-rw-r--r--ext/standard/tests/array/bug71334.phpt38
-rw-r--r--ext/standard/tests/array/unexpected_array_mod_bug.phpt21
-rw-r--r--ext/standard/tests/array/unexpected_array_mod_bug_variation1.phpt33
12 files changed, 159 insertions, 88 deletions
diff --git a/NEWS b/NEWS
index abf70d04c1..b81998b5d2 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,7 @@ PHP NEWS
. Fixed bug #62059 (ArrayObject and isset are not friends). (Nikita)
. Fixed bug #71871 (Interfaces allow final and abstract functions). (Nikita)
. Fixed bug #71922 (Crash on assert(new class{})). (Nikita)
+ . Fixed bug #71334 (Cannot access array keys while uksort()). (Nikita)
- Curl:
. Fixed bug #71831 (CURLOPT_NOPROXY applied as long instead of string).
@@ -32,8 +33,8 @@ PHP NEWS
(Daniel kalaspuffar, Julien)
- Postgres:
- . Fixed bug #71820 (pg_fetch_object binds parameters before
- call constructor). (Anatol)
+ . Fixed bug #71820 (pg_fetch_object binds parameters before call
+ constructor). (Anatol)
- SPL:
. Fixed bug #71838 (Deserializing serialized SPLObjectStorage-Object can't
@@ -116,8 +117,7 @@ PHP NEWS
(steven dot lambeth at gmx dot de, Anatol)
- Phar:
- . Fixed bug #71625 (Crash in php7.dll with bad phar filename).
- (Anatol)
+ . Fixed bug #71625 (Crash in php7.dll with bad phar filename). (Anatol)
. Fixed bug #71317 (PharData fails to open specific file). (Jos Elstgeest)
. Fixed bug #71860 (Invalid memory write in phar on filename with \0 in
name). (Stas)
@@ -126,7 +126,7 @@ PHP NEWS
. Fixed crash when advancing (except step) inside an internal function. (Bob)
- Session:
- . Fixed Bug #71683 (Null pointer dereference in zend_hash_str_find_bucket).
+ . Fixed bug #71683 (Null pointer dereference in zend_hash_str_find_bucket).
(Yasuo)
- SNMP:
diff --git a/Zend/tests/closure_invoke_case_insensitive.phpt b/Zend/tests/closure_invoke_case_insensitive.phpt
new file mode 100644
index 0000000000..d41d58a747
--- /dev/null
+++ b/Zend/tests/closure_invoke_case_insensitive.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Closure::__invoke() is case insensitive
+--FILE--
+<?php
+
+$inc = function(&$n) {
+ $n++;
+};
+
+$n = 1;
+$inc->__INVOKE($n);
+var_dump($n);
+
+?>
+--EXPECT--
+int(2)
diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index 9b4fb1180e..def114c4ec 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -297,14 +297,10 @@ ZEND_API zval* zend_get_closure_this_ptr(zval *obj) /* {{{ */
static zend_function *zend_closure_get_method(zend_object **object, zend_string *method, const zval *key) /* {{{ */
{
- zend_string *lc_name;
-
- lc_name = zend_string_tolower(method);
- if (zend_string_equals_literal(method, ZEND_INVOKE_FUNC_NAME)) {
- zend_string_release(lc_name);
+ if (zend_string_equals_literal_ci(method, ZEND_INVOKE_FUNC_NAME)) {
return zend_get_closure_invoke_method(*object);
}
- zend_string_release(lc_name);
+
return std_object_handlers.get_method(object, method, key);
}
/* }}} */
diff --git a/ext/fileinfo/libmagic/funcs.c b/ext/fileinfo/libmagic/funcs.c
index 6ade713efa..9ea5386ebf 100644
--- a/ext/fileinfo/libmagic/funcs.c
+++ b/ext/fileinfo/libmagic/funcs.c
@@ -403,7 +403,7 @@ file_check_mem(struct magic_set *ms, unsigned int level)
size_t len;
if (level >= ms->c.len) {
- len = (ms->c.len += 20 + level) * sizeof(*ms->c.li);
+ len = (ms->c.len = 20 + level) * sizeof(*ms->c.li);
ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ?
emalloc(len) :
erealloc(ms->c.li, len));
diff --git a/ext/fileinfo/tests/bug68996.phpt b/ext/fileinfo/tests/bug68996.phpt
index da208d35bc..214e52fa6f 100644
--- a/ext/fileinfo/tests/bug68996.phpt
+++ b/ext/fileinfo/tests/bug68996.phpt
@@ -1,11 +1,14 @@
--TEST--
Bug #68996 (Invalid free of CG(interned_empty_string))
--SKIPIF--
+<?php
+if (getenv("USE_ZEND_ALLOC") !== "0") {
+ print "skip Need Zend MM disabled";
+}
+?>
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
--INI--
html_errors=1
---ENV--
-USE_ZEND_ALLOC=0
--FILE--
<?php
finfo_open(FILEINFO_MIME_TYPE, "\xfc\x63");
diff --git a/ext/shmop/shmop.c b/ext/shmop/shmop.c
index 4fe65ae37d..d647790aa0 100644
--- a/ext/shmop/shmop.c
+++ b/ext/shmop/shmop.c
@@ -203,6 +203,7 @@ PHP_FUNCTION(shmop_open)
}
if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
+ /* please do not add coverage here: the segment would be leaked and impossible to delete via php */
php_error_docref(NULL, E_WARNING, "unable to get shared memory segment information '%s'", strerror(errno));
goto err;
}
diff --git a/ext/shmop/tests/003.phpt b/ext/shmop/tests/003.phpt
deleted file mode 100644
index 1c154f08ca..0000000000
--- a/ext/shmop/tests/003.phpt
+++ /dev/null
@@ -1,33 +0,0 @@
---TEST--
-shmop extension error messages (non-root)
---SKIPIF--
-<?php
- if( substr(PHP_OS, 0, 3) == "WIN") {
- die('skip not for Windows');
- }
- if (!extension_loaded("shmop")) {
- die("skip shmop extension not available");
- }
- if (!extension_loaded("posix")) {
- die("skip posix extension not available");
- }
- if (!posix_geteuid()) {
- die("skip cannot run test as root");
- }
-?>
---FILE--
-<?php
- $hex_shm_id = function(){
- return mt_rand(1338, 9999);
- };
-
-echo '## shmop_open function tests ##', PHP_EOL;
- // warning outputs: unable to get shared memory segment information
- var_dump(shmop_open($hex_shm_id(), 'n', 0, 1024));
-
-?>
---EXPECTF--
-## shmop_open function tests ##
-
-Warning: shmop_open(): unable to get shared memory segment information 'Permission denied' in %s on line %d
-bool(false)
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index d5cb32606e..60cbac5726 100644
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -82,18 +82,18 @@ static inline spl_array_object *spl_array_from_obj(zend_object *obj) /* {{{ */ {
#define Z_SPLARRAY_P(zv) spl_array_from_obj(Z_OBJ_P((zv)))
-static inline HashTable *spl_array_get_hash_table(spl_array_object* intern) { /* {{{ */
+static inline HashTable **spl_array_get_hash_table_ptr(spl_array_object* intern) { /* {{{ */
//??? TODO: Delay duplication for arrays; only duplicate for write operations
if (intern->ar_flags & SPL_ARRAY_IS_SELF) {
if (!intern->std.properties) {
rebuild_object_properties(&intern->std);
}
- return intern->std.properties;
+ return &intern->std.properties;
} else if (intern->ar_flags & SPL_ARRAY_USE_OTHER) {
spl_array_object *other = Z_SPLARRAY_P(&intern->array);
- return spl_array_get_hash_table(other);
+ return spl_array_get_hash_table_ptr(other);
} else if (Z_TYPE(intern->array) == IS_ARRAY) {
- return Z_ARRVAL(intern->array);
+ return &Z_ARRVAL(intern->array);
} else {
zend_object *obj = Z_OBJ(intern->array);
if (!obj->properties) {
@@ -104,9 +104,22 @@ static inline HashTable *spl_array_get_hash_table(spl_array_object* intern) { /*
}
obj->properties = zend_array_dup(obj->properties);
}
- return obj->properties;
+ return &obj->properties;
}
-} /* }}} */
+}
+/* }}} */
+
+static inline HashTable *spl_array_get_hash_table(spl_array_object* intern) { /* {{{ */
+ return *spl_array_get_hash_table_ptr(intern);
+}
+/* }}} */
+
+static inline void spl_array_replace_hash_table(spl_array_object* intern, HashTable *ht) { /* {{{ */
+ HashTable **ht_ptr = spl_array_get_hash_table_ptr(intern);
+ zend_array_destroy(*ht_ptr);
+ *ht_ptr = ht;
+}
+/* }}} */
static inline zend_bool spl_array_is_object(spl_array_object *intern) /* {{{ */
{
@@ -1432,16 +1445,12 @@ static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fnam
spl_array_object *intern = Z_SPLARRAY_P(getThis());
HashTable *aht = spl_array_get_hash_table(intern);
zval function_name, params[2], *arg = NULL;
- uint32_t old_refcount;
ZVAL_STRINGL(&function_name, fname, fname_len);
- /* A tricky way to pass "aht" by reference, reset refcount */
- //??? It may be not safe, if user comparison handler accesses "aht"
- old_refcount = GC_REFCOUNT(aht);
- GC_REFCOUNT(aht) = 1;
ZVAL_NEW_EMPTY_REF(&params[0]);
ZVAL_ARR(Z_REFVAL(params[0]), aht);
+ GC_REFCOUNT(aht)++;
if (!use_arg) {
intern->nApplyCount++;
@@ -1470,10 +1479,16 @@ static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fnam
}
exit:
- /* A tricky way to pass "aht" by reference, copy back and cleanup */
- GC_REFCOUNT(aht) = old_refcount;
- efree(Z_REF(params[0]));
- zend_string_free(Z_STR(function_name));
+ {
+ HashTable *new_ht = Z_ARRVAL_P(Z_REFVAL(params[0]));
+ if (aht != new_ht) {
+ spl_array_replace_hash_table(intern, new_ht);
+ } else {
+ GC_REFCOUNT(aht)--;
+ }
+ efree(Z_REF(params[0]));
+ zend_string_free(Z_STR(function_name));
+ }
} /* }}} */
#define SPL_ARRAY_METHOD(cname, fname, use_arg) \
diff --git a/ext/standard/array.c b/ext/standard/array.c
index 4ff373a0b0..289870ac1f 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -1035,37 +1035,30 @@ static int php_array_user_compare(const void *a, const void *b) /* {{{ */
static void php_usort(INTERNAL_FUNCTION_PARAMETERS, compare_func_t compare_func, zend_bool renumber) /* {{{ */
{
zval *array;
- zend_refcounted *arr;
+ zend_array *arr;
zend_bool retval;
PHP_ARRAY_CMP_FUNC_VARS;
PHP_ARRAY_CMP_FUNC_BACKUP();
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/f", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
PHP_ARRAY_CMP_FUNC_RESTORE();
return;
}
- /* Increase reference counter, so the attempts to modify the array in user
- * comparison function will create a copy of array and won't affect the
- * original array. The fact of modification is detected by comparing the
- * zend_array pointer. The result of sorting in such case is undefined and
- * the function returns FALSE.
- */
- Z_ADDREF_P(array);
- arr = Z_COUNTED_P(array);
+ arr = Z_ARR_P(array);
+ if (zend_hash_num_elements(arr) == 0) {
+ PHP_ARRAY_CMP_FUNC_RESTORE();
+ RETURN_TRUE;
+ }
- retval = zend_hash_sort(Z_ARRVAL_P(array), compare_func, renumber) != FAILURE;
+ /* Copy array, so the in-place modifications will not be visible to the callback function */
+ arr = zend_array_dup(arr);
- if (arr != Z_COUNTED_P(array)) {
- php_error_docref(NULL, E_WARNING, "Array was modified by the user comparison function");
- if (--GC_REFCOUNT(arr) <= 0) {
- _zval_dtor_func(arr ZEND_FILE_LINE_CC);
- }
- retval = 0;
- } else {
- Z_DELREF_P(array);
- }
+ retval = zend_hash_sort(arr, compare_func, renumber) != FAILURE;
+
+ zval_ptr_dtor(array);
+ ZVAL_ARR(array, arr);
PHP_ARRAY_CMP_FUNC_RESTORE();
RETURN_BOOL(retval);
diff --git a/ext/standard/tests/array/bug71334.phpt b/ext/standard/tests/array/bug71334.phpt
new file mode 100644
index 0000000000..7a37d0953a
--- /dev/null
+++ b/ext/standard/tests/array/bug71334.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Bug #71334: Cannot access array keys while uksort()
+--FILE--
+<?php
+
+class myClass
+{
+ private $a = [
+ 'foo-test' => [1],
+ '-' => [2],
+ 'bar-test' => [3]
+ ];
+
+ private function _mySort($x, $y)
+ {
+ if (!isset($this->a[$x])) {
+ throw new Exception('Missing X: "' . $x . '"');
+ }
+
+ if (!isset($this->a[$y])) {
+ throw new Exception('Missing Y: "' . $y . '"');
+ }
+
+ return $x < $y;
+ }
+
+ public function __construct()
+ {
+ uksort($this->a, [$this, '_mySort']);
+ }
+}
+
+new myClass();
+echo "Done";
+
+?>
+--EXPECT--
+Done
diff --git a/ext/standard/tests/array/unexpected_array_mod_bug.phpt b/ext/standard/tests/array/unexpected_array_mod_bug.phpt
index 58f2249205..2762ebd830 100644
--- a/ext/standard/tests/array/unexpected_array_mod_bug.phpt
+++ b/ext/standard/tests/array/unexpected_array_mod_bug.phpt
@@ -4,7 +4,7 @@ Crash when function parameter modified via reference
<?php
function usercompare($a,$b) {
unset($GLOBALS['my_var'][2]);
- return 0;
+ return $a <=> $b;
}
$my_var = array(1 => "entry_1",
2 => "entry_2",
@@ -12,10 +12,19 @@ $my_var = array(1 => "entry_1",
4 => "entry_4",
5 => "entry_5");
usort($my_var, "usercompare");
+var_dump($my_var);
-echo "Done.\n";
?>
---EXPECTF--
-
-Warning: usort(): Array was modified by the user comparison function in %s on line %d
-Done.
+--EXPECT--
+array(5) {
+ [0]=>
+ string(7) "entry_1"
+ [1]=>
+ string(7) "entry_2"
+ [2]=>
+ string(7) "entry_3"
+ [3]=>
+ string(7) "entry_4"
+ [4]=>
+ string(7) "entry_5"
+}
diff --git a/ext/standard/tests/array/unexpected_array_mod_bug_variation1.phpt b/ext/standard/tests/array/unexpected_array_mod_bug_variation1.phpt
new file mode 100644
index 0000000000..b5a1ee24d5
--- /dev/null
+++ b/ext/standard/tests/array/unexpected_array_mod_bug_variation1.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Crash when function parameter modified via reference while keeping orig refcount
+--FILE--
+<?php
+
+$array = array(
+ 1 => "entry_1",
+ 2 => "entry_2",
+ 3 => "entry_3",
+ 4 => "entry_4",
+ 5 => "entry_5"
+);
+usort($array, function($a, $b) use (&$array, &$ref) {
+ unset($array[2]);
+ $ref = $array;
+ return $a <=> $b;
+});
+var_dump($array);
+
+?>
+--EXPECT--
+array(5) {
+ [0]=>
+ string(7) "entry_1"
+ [1]=>
+ string(7) "entry_2"
+ [2]=>
+ string(7) "entry_3"
+ [3]=>
+ string(7) "entry_4"
+ [4]=>
+ string(7) "entry_5"
+}