]> granicus.if.org Git - php/commitdiff
Make convert_to_* safe with rc>1
authorNikita Popov <nikic@php.net>
Thu, 11 Jun 2015 17:41:43 +0000 (19:41 +0200)
committerNikita Popov <nikic@php.net>
Thu, 11 Jun 2015 21:23:57 +0000 (23:23 +0200)
This only involves switching zval_dtor to zval_ptr_dtor for arrays
and making the convert_to_object for arrays a bit more generic.

All the other changes outside zend_operators.c just make use of
this new ability (use COPY instead of DUP).

What's still missing: Proper references handling. I've seen many
convert_to* calls that will break when a reference is used.

Also fixes bug #69788.

18 files changed:
Zend/tests/bug69788.phpt [new file with mode: 0644]
Zend/zend_object_handlers.c
Zend/zend_operators.c
Zend/zend_operators.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/iconv/iconv.c
ext/mysqli/mysqli.c
ext/openssl/openssl.c
ext/pgsql/pgsql.c
ext/simplexml/simplexml.c
ext/soap/php_encoding.c
ext/spl/spl_iterators.c
ext/standard/array.c
ext/standard/http.c
ext/standard/password.c
ext/standard/type.c
ext/zip/php_zip.c

diff --git a/Zend/tests/bug69788.phpt b/Zend/tests/bug69788.phpt
new file mode 100644 (file)
index 0000000..e484866
--- /dev/null
@@ -0,0 +1,8 @@
+--TEST--
+Bug #69788: Malformed script causes Uncaught EngineException in php-cgi, valgrind SIGILL
+--FILE--
+<?php [t.[]]; ?>
+--EXPECTF--
+Notice: Array to string conversion in %s on line %d
+
+Notice: Use of undefined constant t - assumed 't' in %s on line %d
index 259679a57fd81d1aa81613e65129eb27396c8093..74ae382df4bb5280e9cc4cc758897deb61267b2d 100644 (file)
@@ -672,7 +672,7 @@ write_std_property:
                if (Z_REFCOUNTED_P(value)) {
                        if (Z_ISREF_P(value)) {
                                /* if we assign referenced variable, we should separate it */
-                               ZVAL_DUP(&tmp, Z_REFVAL_P(value));
+                               ZVAL_COPY(&tmp, Z_REFVAL_P(value));
                                value = &tmp;
                        } else {
                                Z_ADDREF_P(value);
index aa20bcaf59170476b4b4e4d80a1ad4efbd479e2d..a6172179f5bd9e0c1916d0187a5437136cecfece 100644 (file)
@@ -209,7 +209,7 @@ try_again:
                                (op) = &(holder);                                                                                       \
                                break;                                                                                                          \
                        case IS_OBJECT:                                                                                                 \
-                               ZVAL_DUP(&(holder), op);                                                                                \
+                               ZVAL_COPY(&(holder), op);                                                                               \
                                convert_to_long_base(&(holder), 10);                                            \
                                if (Z_TYPE(holder) == IS_LONG) {                                                        \
                                        (op) = &(holder);                                                                               \
@@ -312,7 +312,7 @@ ZEND_API void ZEND_FASTCALL convert_to_long_base(zval *op, int base) /* {{{ */
                        break;
                case IS_ARRAY:
                        tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
-                       zval_dtor(op);
+                       zval_ptr_dtor(op);
                        ZVAL_LONG(op, tmp);
                        break;
                case IS_OBJECT:
@@ -369,7 +369,7 @@ ZEND_API void ZEND_FASTCALL convert_to_double(zval *op) /* {{{ */
                        break;
                case IS_ARRAY:
                        tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
-                       zval_dtor(op);
+                       zval_ptr_dtor(op);
                        ZVAL_DOUBLE(op, tmp);
                        break;
                case IS_OBJECT:
@@ -408,7 +408,7 @@ ZEND_API void ZEND_FASTCALL convert_to_null(zval *op) /* {{{ */
                }
        }
 
-       zval_dtor(op);
+       zval_ptr_dtor(op);
        ZVAL_NULL(op);
 }
 /* }}} */
@@ -452,7 +452,7 @@ ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op) /* {{{ */
                        break;
                case IS_ARRAY:
                        tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
-                       zval_dtor(op);
+                       zval_ptr_dtor(op);
                        ZVAL_BOOL(op, tmp);
                        break;
                case IS_OBJECT:
@@ -516,7 +516,7 @@ ZEND_API void ZEND_FASTCALL _convert_to_string(zval *op ZEND_FILE_LINE_DC) /* {{
                }
                case IS_ARRAY:
                        zend_error(E_NOTICE, "Array to string conversion");
-                       zval_dtor(op);
+                       zval_ptr_dtor(op);
                        ZVAL_NEW_STR(op, zend_string_init("Array", sizeof("Array")-1, 0));
                        break;
                case IS_OBJECT: {
@@ -603,14 +603,10 @@ ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) /* {{{ */
        switch (Z_TYPE_P(op)) {
                case IS_ARRAY:
                        {
-                               HashTable *properties = emalloc(sizeof(HashTable));
-                               zend_array *arr = Z_ARR_P(op);
-
-                               memcpy(properties, Z_ARRVAL_P(op), sizeof(HashTable));
-                               object_and_properties_init(op, zend_standard_class_def, properties);
-                               if (--GC_REFCOUNT(arr) == 0) {
-                                       efree_size(arr, sizeof(zend_array));
-                               }
+                               zval tmp;
+                               ZVAL_COPY_VALUE(&tmp, op);
+                               SEPARATE_ARRAY(&tmp);
+                               object_and_properties_init(op, zend_standard_class_def, Z_ARR(tmp));
                                break;
                        }
                case IS_OBJECT:
index c026f23415969b549174d81d2b13a3cd35cf72e8..17d1bcffb489d0221b4373953e2dd47249975469 100644 (file)
@@ -364,7 +364,6 @@ ZEND_API void ZEND_FASTCALL zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_D
 
 #define convert_to_ex_master(pzv, lower_type, upper_type)      \
        if (Z_TYPE_P(pzv)!=upper_type) {                                        \
-               SEPARATE_ZVAL_IF_NOT_REF(pzv);                                          \
                convert_to_##lower_type(pzv);                                           \
        }
 
@@ -400,7 +399,6 @@ ZEND_API void ZEND_FASTCALL zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_D
 
 #define convert_to_explicit_type_ex(pzv, str_type)     \
        if (Z_TYPE_P(pzv) != str_type) {                                \
-               SEPARATE_ZVAL_IF_NOT_REF(pzv);                          \
                convert_to_explicit_type(pzv, str_type);        \
        }
 
@@ -414,7 +412,6 @@ ZEND_API void ZEND_FASTCALL zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_D
 
 #define convert_scalar_to_number_ex(pzv)                                                       \
        if (Z_TYPE_P(pzv)!=IS_LONG && Z_TYPE_P(pzv)!=IS_DOUBLE) {               \
-               SEPARATE_ZVAL_IF_NOT_REF(pzv);                                                          \
                convert_scalar_to_number(pzv);                                  \
        }
 
index 568d61e0cad9bae4384121859df7682a5ee731a9..0fe820a20fa62a114ce60c729c4ce1536d9f9b43 100644 (file)
@@ -5432,8 +5432,7 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY)
                                                }
                                        }
                                } else {
-                                       ZVAL_COPY_VALUE(result, expr);
-                                       zval_opt_copy_ctor(result);
+                                       ZVAL_COPY(result, expr);
                                        convert_to_object(result);
                                }
                        }
index a0bb1012b25c7d011501ed6ca10d0fb01ff1ebde..1ab12b7779e909ccd388e493064e350d9310cec9 100644 (file)
@@ -3730,8 +3730,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_HANDLER(ZEND_O
                                                }
                                        }
                                } else {
-                                       ZVAL_COPY_VALUE(result, expr);
-                                       zval_opt_copy_ctor(result);
+                                       ZVAL_COPY(result, expr);
                                        convert_to_object(result);
                                }
                        }
@@ -12350,8 +12349,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC
                                                }
                                        }
                                } else {
-                                       ZVAL_COPY_VALUE(result, expr);
-                                       zval_opt_copy_ctor(result);
+                                       ZVAL_COPY(result, expr);
                                        convert_to_object(result);
                                }
                        }
@@ -15827,8 +15825,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC
                                                }
                                        }
                                } else {
-                                       ZVAL_COPY_VALUE(result, expr);
-                                       zval_opt_copy_ctor(result);
+                                       ZVAL_COPY(result, expr);
                                        convert_to_object(result);
                                }
                        }
@@ -29481,8 +29478,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO
                                                }
                                        }
                                } else {
-                                       ZVAL_COPY_VALUE(result, expr);
-                                       zval_opt_copy_ctor(result);
+                                       ZVAL_COPY(result, expr);
                                        convert_to_object(result);
                                }
                        }
index 8042916c0dd98fd34ea6ce776cbe1ac03de2c271..897185da8a91016cabe2e2d40ab791c7f35c8a8b 100644 (file)
@@ -2209,8 +2209,8 @@ PHP_FUNCTION(iconv_mime_encode)
 {
        zend_string *field_name = NULL;
        zend_string *field_value = NULL;
+       zend_string *tmp_str = NULL;
        zval *pref = NULL;
-       zval tmp_zv, *tmp_zv_p = NULL;
        smart_str retval = {0};
        php_iconv_err_t err;
 
@@ -2273,12 +2273,8 @@ PHP_FUNCTION(iconv_mime_encode)
 
                if ((pzval = zend_hash_str_find(Z_ARRVAL_P(pref), "line-break-chars", sizeof("line-break-chars") - 1)) != NULL) {
                        if (Z_TYPE_P(pzval) != IS_STRING) {
-                               ZVAL_DUP(&tmp_zv, pzval);
-                               convert_to_string(&tmp_zv);
-
-                               lfchars = Z_STRVAL(tmp_zv);
-
-                               tmp_zv_p = &tmp_zv;
+                               tmp_str = zval_get_string(pzval);
+                               lfchars = tmp_str->val;
                        } else {
                                lfchars = Z_STRVAL_P(pzval);
                        }
@@ -2301,8 +2297,8 @@ PHP_FUNCTION(iconv_mime_encode)
                RETVAL_FALSE;
        }
 
-       if (tmp_zv_p != NULL) {
-               zval_dtor(tmp_zv_p);
+       if (tmp_str) {
+               zend_string_release(tmp_str);
        }
 }
 /* }}} */
index 9bc81769d5bc28703f22099320f927bb5e779ced..d0766144189c234085dbd32dd84bbda1e094a3f1 100644 (file)
@@ -306,7 +306,7 @@ zval *mysqli_read_property(zval *object, zval *member, int type, void **cache_sl
        obj = Z_MYSQLI_P(object);
 
        if (Z_TYPE_P(member) != IS_STRING) {
-               ZVAL_DUP(&tmp_member, member);
+               ZVAL_COPY(&tmp_member, member);
                convert_to_string(&tmp_member);
                member = &tmp_member;
        }
@@ -341,7 +341,7 @@ void mysqli_write_property(zval *object, zval *member, zval *value, void **cache
        mysqli_prop_handler *hnd = NULL;
 
        if (Z_TYPE_P(member) != IS_STRING) {
-               ZVAL_DUP(&tmp_member, member);
+               ZVAL_COPY(&tmp_member, member);
                convert_to_string(&tmp_member);
                member = &tmp_member;
        }
index d6094e7f1113b19bdc35b15620e54ed344b27755..c79447097de5606f7f804ed9f7bbba9f9a91c7e8 100644 (file)
@@ -3217,7 +3217,7 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval * val, int public_key, char * p
                if (Z_TYPE_P(zphrase) == IS_STRING) {
                        passphrase = Z_STRVAL_P(zphrase);
                } else {
-                       ZVAL_DUP(&tmp, zphrase);
+                       ZVAL_COPY(&tmp, zphrase);
                        convert_to_string(&tmp);
                        passphrase = Z_STRVAL(tmp);
                }
index a65b7a0aa9f2b5eef17312528d16f738a0d5a8a8..696558915431962f46b695fcde0d13dec71fcc5e 100644 (file)
@@ -4246,7 +4246,7 @@ PHP_FUNCTION(pg_copy_from)
 #if HAVE_PQPUTCOPYDATA
                                ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), value) {
                                        zval tmp;
-                                       ZVAL_DUP(&tmp, value);
+                                       ZVAL_COPY(&tmp, value);
                                        convert_to_string_ex(&tmp);
                                        query = (char *)emalloc(Z_STRLEN(tmp) + 2);
                                        strlcpy(query, Z_STRVAL(tmp), Z_STRLEN(tmp) + 2);
@@ -4270,7 +4270,7 @@ PHP_FUNCTION(pg_copy_from)
 #else
                                ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), value) {
                                        zval tmp;
-                                       ZVAL_DUP(&tmp, value);
+                                       ZVAL_COPY(&tmp, value);
                                        convert_to_string_ex(&tmp);
                                        query = (char *)emalloc(Z_STRLEN(tmp) + 2);
                                        strlcpy(query, Z_STRVAL(tmp), Z_STRLEN(tmp) + 2);
index 6bcf12ea86951c43386d6090bd6b60ec5a6e05c3..2d9e6fd3398aa34fca490fd6918849bdaa33bfe5 100644 (file)
@@ -517,7 +517,7 @@ static int sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool
                        case IS_DOUBLE:
                        case IS_NULL:
                                if (Z_TYPE_P(value) != IS_STRING) {
-                                       ZVAL_DUP(&zval_copy, value);
+                                       ZVAL_COPY(&zval_copy, value);
                                        value = &zval_copy;
                                        convert_to_string(value);
                                        new_value = 1;
index 96207f797512af22bd04d511b48e99c39162db4a..7bff2aeab67c1c42fbc0a730e4b72942beadc8be 100644 (file)
@@ -923,21 +923,16 @@ static xmlNodePtr to_xml_base64(encodeTypePtr type, zval *data, int style, xmlNo
 
        if (Z_TYPE_P(data) == IS_STRING) {
                str = php_base64_encode((unsigned char*)Z_STRVAL_P(data), Z_STRLEN_P(data));
-               text = xmlNewTextLen(BAD_CAST(str->val), str->len);
-               xmlAddChild(ret, text);
-               zend_string_release(str);
        } else {
-               zval tmp;
-
-               ZVAL_DUP(&tmp, data);
-               convert_to_string(&tmp);
-               str = php_base64_encode((unsigned char*)Z_STRVAL(tmp), Z_STRLEN(tmp));
-               text = xmlNewTextLen(BAD_CAST(str->val), str->len);
-               xmlAddChild(ret, text);
-               zend_string_release(str);
-               zval_dtor(&tmp);
+               zend_string *tmp = zval_get_string(data);
+               str = php_base64_encode((unsigned char*) tmp->val, tmp->len);
+               zend_string_release(tmp);
        }
 
+       text = xmlNewTextLen(BAD_CAST(str->val), str->len);
+       xmlAddChild(ret, text);
+       zend_string_release(str);
+
        if (style == SOAP_ENCODED) {
                set_ns_and_type(ret, type);
        }
index 37f97866c72d33af0442a935cb0777e580bf0121..8f77d7088e76f2dfd9407b308605041c2aff81ca 100644 (file)
@@ -2074,8 +2074,7 @@ SPL_METHOD(RegexIterator, accept)
                case REGIT_MODE_REPLACE:
                        replacement = zend_read_property(intern->std.ce, getThis(), "replacement", sizeof("replacement")-1, 1, &rv);
                        if (Z_TYPE_P(replacement) != IS_STRING) {
-                               tmp_replacement = *replacement;
-                               zval_copy_ctor(&tmp_replacement);
+                               ZVAL_COPY(&tmp_replacement, replacement);
                                convert_to_string(&tmp_replacement);
                                replacement = &tmp_replacement;
                        }
@@ -2787,11 +2786,11 @@ SPL_METHOD(CachingIterator, __toString)
                return;
        }
        if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) {
-               ZVAL_DUP(return_value, &intern->current.key);
+               ZVAL_COPY(return_value, &intern->current.key);
                convert_to_string(return_value);
                return;
        } else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) {
-               ZVAL_DUP(return_value, &intern->current.data);
+               ZVAL_COPY(return_value, &intern->current.data);
                convert_to_string(return_value);
                return;
        }
index 519b665df03383dc7fdadbdbfd6acf753879be2e..ca72adfaebee73ff677e5f3eaaacec33d4b21001 100644 (file)
@@ -2588,7 +2588,7 @@ PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */
                                }
                                ZVAL_UNDEF(&tmp);
                                if (Z_TYPE_P(src_zval) == IS_OBJECT) {
-                                       ZVAL_DUP(&tmp, src_zval);
+                                       ZVAL_COPY(&tmp, src_zval);
                                        convert_to_array(&tmp);
                                        src_zval = &tmp;
                                }
@@ -4624,7 +4624,7 @@ PHP_FUNCTION(array_sum)
                if (Z_TYPE_P(entry) == IS_ARRAY || Z_TYPE_P(entry) == IS_OBJECT) {
                        continue;
                }
-               ZVAL_DUP(&entry_n, entry);
+               ZVAL_COPY(&entry_n, entry);
                convert_scalar_to_number(&entry_n);
                fast_add_function(return_value, return_value, &entry_n);
        } ZEND_HASH_FOREACH_END();
@@ -4653,7 +4653,7 @@ PHP_FUNCTION(array_product)
                if (Z_TYPE_P(entry) == IS_ARRAY || Z_TYPE_P(entry) == IS_OBJECT) {
                        continue;
                }
-               ZVAL_DUP(&entry_n, entry);
+               ZVAL_COPY(&entry_n, entry);
                convert_scalar_to_number(&entry_n);
 
                if (Z_TYPE(entry_n) == IS_LONG && Z_TYPE_P(return_value) == IS_LONG) {
index 25b77280de9f374c25ee9f917e7da3919e25bbd5..7fe094009eab69816b28bf274123e74dd639a57c 100644 (file)
@@ -36,7 +36,7 @@ PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr,
        const char *prop_name;
        size_t arg_sep_len, newprefix_len, prop_len;
        zend_ulong idx;
-       zval *zdata = NULL, copyzval;
+       zval *zdata = NULL;
 
        if (!ht) {
                return FAILURE;
@@ -204,16 +204,14 @@ PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr,
                                default:
                                        {
                                                zend_string *ekey;
-                                               /* fall back on convert to string */
-                                               ZVAL_DUP(&copyzval, zdata);
-                                               convert_to_string_ex(&copyzval);
+                                               zend_string *tmp = zval_get_string(zdata);
                                                if (enc_type == PHP_QUERY_RFC3986) {
-                                                       ekey = php_raw_url_encode(Z_STRVAL(copyzval), Z_STRLEN(copyzval));
+                                                       ekey = php_raw_url_encode(tmp->val, tmp->len);
                                                } else {
-                                                       ekey = php_url_encode(Z_STRVAL(copyzval), Z_STRLEN(copyzval));
+                                                       ekey = php_url_encode(tmp->val, tmp->len);
                                                }
                                                smart_str_append(formstr, ekey);
-                                               zval_ptr_dtor(&copyzval);
+                                               zend_string_release(tmp);
                                                zend_string_free(ekey);
                                        }
                        }
index 4ad955e0185493eccfb87558ca70b393dc2dd52b..592f41838df1ec6ddc390ec54f610fc3b1d71073 100644 (file)
@@ -340,18 +340,13 @@ PHP_FUNCTION(password_hash)
                                break;
                        case IS_LONG:
                        case IS_DOUBLE:
-                       case IS_OBJECT: {
-                               zval cast_option_buffer;
-
-                               ZVAL_DUP(&cast_option_buffer, option_buffer);
-                               convert_to_string(&cast_option_buffer);
-                               if (Z_TYPE(cast_option_buffer) == IS_STRING) {
-                                       buffer = estrndup(Z_STRVAL(cast_option_buffer), Z_STRLEN(cast_option_buffer));
-                                       buffer_len = Z_STRLEN(cast_option_buffer);
-                                       zval_dtor(&cast_option_buffer);
-                                       break;
-                               }
-                               zval_dtor(&cast_option_buffer);
+                       case IS_OBJECT:
+                       {
+                               zend_string *tmp = zval_get_string(option_buffer);
+                               buffer = estrndup(tmp->val, tmp->len);
+                               buffer_len = tmp->len;
+                               zend_string_release(tmp);
+                               break;
                        }
                        case IS_FALSE:
                        case IS_TRUE:
index f884017f6f8ec9a6c106767cdcd6e46f720b3337..fdf0febe7af69f3c6c3e2fbbf21fd761cc67ec99 100644 (file)
@@ -101,7 +101,6 @@ PHP_FUNCTION(settype)
        }
 
        ZVAL_DEREF(var);
-       SEPARATE_ZVAL_NOREF(var);
        if (!strcasecmp(type, "integer")) {
                convert_to_long(var);
        } else if (!strcasecmp(type, "int")) {
index 1dd76fcba8e45d3df2fbac32f165a7ea6d9fe693..7c17fb983aa26b1387ca1f67ef146aeeaf4753f3 100644 (file)
@@ -847,7 +847,7 @@ static zval *php_zip_get_property_ptr_ptr(zval *object, zval *member, int type,
        zend_object_handlers *std_hnd;
 
        if (Z_TYPE_P(member) != IS_STRING) {
-               ZVAL_DUP(&tmp_member, member);
+               ZVAL_COPY(&tmp_member, member);
                convert_to_string(&tmp_member);
                member = &tmp_member;
                cache_slot = NULL;
@@ -881,7 +881,7 @@ static zval *php_zip_read_property(zval *object, zval *member, int type, void **
        zend_object_handlers *std_hnd;
 
        if (Z_TYPE_P(member) != IS_STRING) {
-               ZVAL_DUP(&tmp_member, member);
+               ZVAL_COPY(&tmp_member, member);
                convert_to_string(&tmp_member);
                member = &tmp_member;
                cache_slot = NULL;
@@ -920,7 +920,7 @@ static int php_zip_has_property(zval *object, zval *member, int type, void **cac
        int retval = 0;
 
        if (Z_TYPE_P(member) != IS_STRING) {
-               ZVAL_DUP(&tmp_member, member);
+               ZVAL_COPY(&tmp_member, member);
                convert_to_string(&tmp_member);
                member = &tmp_member;
                cache_slot = NULL;