diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-02-26 15:32:18 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-06-05 14:25:07 +0200 |
commit | a31f46421d7bf6f55dd9ac5876b8e2eacf7e0708 (patch) | |
tree | 24ffd7c5ae5e321c3994048fdd0fd9f68ae7457c /ext | |
parent | 528aa7932a839fc6319979c34aa372805d8dc41c (diff) | |
download | php-git-a31f46421d7bf6f55dd9ac5876b8e2eacf7e0708.tar.gz |
Allow exceptions in __toString()
RFC: https://wiki.php.net/rfc/tostring_exceptions
And convert some object to string conversion related recoverable
fatal errors into Error exceptions.
Improve exception safety of internal code performing string
conversions.
Diffstat (limited to 'ext')
83 files changed, 913 insertions, 313 deletions
diff --git a/ext/date/php_date.c b/ext/date/php_date.c index f7db8a26d7..3e8fb419d8 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -2043,6 +2043,9 @@ static int date_interval_has_property(zval *object, zval *member, int type, void ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; cache_slot = NULL; + if (EG(exception)) { + return 0; + } } obj = Z_PHPINTERVAL_P(object); @@ -4167,6 +4170,9 @@ static zval *date_interval_read_property(zval *object, zval *member, int type, v ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; cache_slot = NULL; + if (EG(exception)) { + return &EG(uninitialized_zval); + } } obj = Z_PHPINTERVAL_P(object); @@ -4235,6 +4241,9 @@ static zval *date_interval_write_property(zval *object, zval *member, zval *valu ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; cache_slot = NULL; + if (EG(exception)) { + return value; + } } obj = Z_PHPINTERVAL_P(object); @@ -4286,6 +4295,9 @@ static zval *date_interval_get_property_ptr_ptr(zval *object, zval *member, int ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; cache_slot = NULL; + if (EG(exception)) { + return NULL; + } } if(zend_binary_strcmp("y", sizeof("y") - 1, Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0 || diff --git a/ext/dba/dba.c b/ext/dba/dba.c index ede12f0bd6..952993582b 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -672,6 +672,12 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, int persistent) keylen += Z_STRLEN(args[i]); } + /* Exception during string conversion */ + if (EG(exception)) { + FREENOW; + return; + } + if (persistent) { zend_resource *le; diff --git a/ext/dom/attr.c b/ext/dom/attr.c index f59b46799f..0255708517 100644 --- a/ext/dom/attr.c +++ b/ext/dom/attr.c @@ -160,12 +160,15 @@ int dom_attr_value_write(dom_object *obj, zval *newval) return FAILURE; } + str = zval_get_string(newval); + if (EG(exception)) { + return FAILURE; + } + if (attrp->children) { node_list_unlink(attrp->children); } - str = zval_get_string(newval); - xmlNodeSetContentLen((xmlNodePtr) attrp, (xmlChar *) ZSTR_VAL(str), ZSTR_LEN(str) + 1); zend_string_release_ex(str, 0); diff --git a/ext/dom/characterdata.c b/ext/dom/characterdata.c index f473240498..7676370677 100644 --- a/ext/dom/characterdata.c +++ b/ext/dom/characterdata.c @@ -105,6 +105,9 @@ int dom_characterdata_data_write(dom_object *obj, zval *newval) } str = zval_get_string(newval); + if (EG(exception)) { + return FAILURE; + } xmlNodeSetContentLen(nodep, (xmlChar *) ZSTR_VAL(str), ZSTR_LEN(str) + 1); diff --git a/ext/dom/document.c b/ext/dom/document.c index 95b077b648..235323e1d7 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -338,6 +338,9 @@ int dom_document_encoding_write(dom_object *obj, zval *newval) } str = zval_get_string(newval); + if (EG(exception)) { + return FAILURE; + } handler = xmlFindCharEncodingHandler(Z_STRVAL_P(newval)); @@ -431,12 +434,15 @@ int dom_document_version_write(dom_object *obj, zval *newval) return FAILURE; } + str = zval_get_string(newval); + if (EG(exception)) { + return FAILURE; + } + if (docp->version != NULL) { xmlFree((xmlChar *) docp->version ); } - str = zval_get_string(newval); - docp->version = xmlStrdup((const xmlChar *) ZSTR_VAL(str)); zend_string_release_ex(str, 0); @@ -659,12 +665,15 @@ int dom_document_document_uri_write(dom_object *obj, zval *newval) return FAILURE; } + str = zval_get_string(newval); + if (EG(exception)) { + return FAILURE; + } + if (docp->URL != NULL) { xmlFree((xmlChar *) docp->URL); } - str = zval_get_string(newval); - docp->URL = xmlStrdup((const xmlChar *) ZSTR_VAL(str)); zend_string_release_ex(str, 0); diff --git a/ext/dom/node.c b/ext/dom/node.c index 03e61efa67..44e6f58b30 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -323,12 +323,18 @@ int dom_node_node_value_read(dom_object *obj, zval *retval) int dom_node_node_value_write(dom_object *obj, zval *newval) { xmlNode *nodep = dom_object_get_node(obj); + zend_string *str; if (nodep == NULL) { php_dom_throw_error(INVALID_STATE_ERR, 0); return FAILURE; } + str = zval_get_string(newval); + if (EG(exception)) { + return FAILURE; + } + /* Access to Element node is implemented as a convenience method */ switch (nodep->type) { case XML_ELEMENT_NODE: @@ -342,16 +348,13 @@ int dom_node_node_value_write(dom_object *obj, zval *newval) case XML_COMMENT_NODE: case XML_CDATA_SECTION_NODE: case XML_PI_NODE: - { - zend_string *str = zval_get_string(newval); - xmlNodeSetContentLen(nodep, (xmlChar *) ZSTR_VAL(str), ZSTR_LEN(str) + 1); - zend_string_release_ex(str, 0); - break; - } + xmlNodeSetContentLen(nodep, (xmlChar *) ZSTR_VAL(str), ZSTR_LEN(str) + 1); + break; default: break; } + zend_string_release_ex(str, 0); return SUCCESS; } @@ -722,6 +725,10 @@ int dom_node_prefix_write(dom_object *obj, zval *newval) } } str = zval_get_string(newval); + if (EG(exception)) { + return FAILURE; + } + prefix = ZSTR_VAL(str); if (nsnode && nodep->ns != NULL && !xmlStrEqual(nodep->ns->prefix, (xmlChar *)prefix)) { strURI = (char *) nodep->ns->href; @@ -854,6 +861,11 @@ int dom_node_text_content_write(dom_object *obj, zval *newval) return FAILURE; } + str = zval_get_string(newval); + if (EG(exception)) { + return FAILURE; + } + if (nodep->type == XML_ELEMENT_NODE || nodep->type == XML_ATTRIBUTE_NODE) { if (nodep->children) { node_list_unlink(nodep->children); @@ -862,7 +874,6 @@ int dom_node_text_content_write(dom_object *obj, zval *newval) } } - str = zval_get_string(newval); /* we have to use xmlNodeAddContent() to get the same behavior as with xmlNewText() */ xmlNodeSetContent(nodep, (xmlChar *) ""); xmlNodeAddContent(nodep, (xmlChar *) ZSTR_VAL(str)); diff --git a/ext/dom/processinginstruction.c b/ext/dom/processinginstruction.c index 0487abc373..103bfd74f0 100644 --- a/ext/dom/processinginstruction.c +++ b/ext/dom/processinginstruction.c @@ -139,6 +139,9 @@ int dom_processinginstruction_data_write(dom_object *obj, zval *newval) } str = zval_get_string(newval); + if (EG(exception)) { + return FAILURE; + } xmlNodeSetContentLen(nodep, (xmlChar *) ZSTR_VAL(str), ZSTR_LEN(str) + 1); diff --git a/ext/dom/tests/toString_exceptions.phpt b/ext/dom/tests/toString_exceptions.phpt new file mode 100644 index 0000000000..e59532d48c --- /dev/null +++ b/ext/dom/tests/toString_exceptions.phpt @@ -0,0 +1,56 @@ +--TEST-- +Handling of exceptions during __toString +--FILE-- +<?php + +class BadStr { + public function __toString() { + throw new Exception("Exception"); + } +} + +$badStr = new BadStr; + +$doc = new DOMDocument(); +$doc->loadXML( + '<root xmlns:ns="foo"><node attr="foo" /><node>Text</node><ns:node/><?pi foobar?></root>'); + +try { $doc->encoding = $badStr; } catch (Exception $e) { echo "Exception\n"; } +try { $doc->version = $badStr; } catch (Exception $e) { echo "Exception\n"; } +try { $doc->documentURI = $badStr; } catch (Exception $e) { echo "Exception\n"; } +$root = $doc->childNodes[0]; + +$node = $root->childNodes[0]; +$attrs = $node->attributes; +$attr = $attrs[0]; +try { $attr->value = $badStr; } catch (Exception $e) { echo "Exception\n"; } +try { $attr->nodeValue = $badStr; } catch (Exception $e) { echo "Exception\n"; } + +$node2 = $root->childNodes[1]; +try { $node2->nodeValue = $badStr; } catch (Exception $e) { echo "Exception\n"; } +try { $node2->textContent = $badStr; } catch (Exception $e) { echo "Exception\n"; } +$data = $node2->childNodes[0]; +try { $data->data = $badStr; } catch (Exception $e) { echo "Exception\n"; } + +$node3 = $root->childNodes[2]; +try { $node3->prefix = $badStr; } catch (Exception $e) { echo "Exception\n"; } + +$pi = $root->childNodes[3]; +try { $pi->data = $badStr; } catch (Exception $e) { echo "Exception\n"; } + +echo $doc->saveXML(); + +?> +--EXPECT-- +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +<?xml version="1.0"?> +<root xmlns:ns="foo"><node attr="foo"/><node>Text</node><ns:node/><?pi foobar?></root> diff --git a/ext/exif/exif.c b/ext/exif/exif.c index 1fd42fe096..0ec5b1a1b8 100644 --- a/ext/exif/exif.c +++ b/ext/exif/exif.c @@ -4419,7 +4419,9 @@ PHP_FUNCTION(exif_read_data) ret = exif_read_from_stream(&ImageInfo, p_stream, read_thumbnail, read_all); } else { - convert_to_string(stream); + if (!try_convert_to_string(stream)) { + return; + } if (!Z_STRLEN_P(stream)) { exif_error_docref(NULL EXIFERR_CC, &ImageInfo, E_WARNING, "Filename cannot be empty"); @@ -4589,7 +4591,9 @@ PHP_FUNCTION(exif_thumbnail) ret = exif_read_from_stream(&ImageInfo, p_stream, 1, 0); } else { - convert_to_string(stream); + if (!try_convert_to_string(stream)) { + return; + } if (!Z_STRLEN_P(stream)) { exif_error_docref(NULL EXIFERR_CC, &ImageInfo, E_WARNING, "Filename cannot be empty"); diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 786589d263..9aa3953918 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -2298,7 +2298,10 @@ PHP_FUNCTION(imagecreatefromstring) return; } - convert_to_string_ex(data); + if (!try_convert_to_string(data)) { + return; + } + if (Z_STRLEN_P(data) < sizeof(sig)) { php_error_docref(NULL, E_WARNING, "Empty string or invalid image"); RETURN_FALSE; diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c index bb40b6a215..688e3a2552 100644 --- a/ext/iconv/iconv.c +++ b/ext/iconv/iconv.c @@ -2243,7 +2243,7 @@ PHP_FUNCTION(iconv_mime_encode) if (pref != NULL) { zval *pzval; - if ((pzval = zend_hash_str_find(Z_ARRVAL_P(pref), "scheme", sizeof("scheme") - 1)) != NULL) { + if ((pzval = zend_hash_str_find_deref(Z_ARRVAL_P(pref), "scheme", sizeof("scheme") - 1)) != NULL) { if (Z_TYPE_P(pzval) == IS_STRING && Z_STRLEN_P(pzval) > 0) { switch (Z_STRVAL_P(pzval)[0]) { case 'B': case 'b': @@ -2257,7 +2257,7 @@ PHP_FUNCTION(iconv_mime_encode) } } - if ((pzval = zend_hash_str_find(Z_ARRVAL_P(pref), "input-charset", sizeof("input-charset") - 1)) != NULL && Z_TYPE_P(pzval) == IS_STRING) { + if ((pzval = zend_hash_str_find_deref(Z_ARRVAL_P(pref), "input-charset", sizeof("input-charset") - 1)) != NULL && Z_TYPE_P(pzval) == IS_STRING) { if (Z_STRLEN_P(pzval) >= ICONV_CSNMAXLEN) { php_error_docref(NULL, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); RETURN_FALSE; @@ -2269,7 +2269,7 @@ PHP_FUNCTION(iconv_mime_encode) } - if ((pzval = zend_hash_str_find(Z_ARRVAL_P(pref), "output-charset", sizeof("output-charset") - 1)) != NULL && Z_TYPE_P(pzval) == IS_STRING) { + if ((pzval = zend_hash_str_find_deref(Z_ARRVAL_P(pref), "output-charset", sizeof("output-charset") - 1)) != NULL && Z_TYPE_P(pzval) == IS_STRING) { if (Z_STRLEN_P(pzval) >= ICONV_CSNMAXLEN) { php_error_docref(NULL, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN); RETURN_FALSE; @@ -2280,13 +2280,16 @@ PHP_FUNCTION(iconv_mime_encode) } } - if ((pzval = zend_hash_str_find(Z_ARRVAL_P(pref), "line-length", sizeof("line-length") - 1)) != NULL) { + if ((pzval = zend_hash_str_find_deref(Z_ARRVAL_P(pref), "line-length", sizeof("line-length") - 1)) != NULL) { line_len = zval_get_long(pzval); } - if ((pzval = zend_hash_str_find(Z_ARRVAL_P(pref), "line-break-chars", sizeof("line-break-chars") - 1)) != NULL) { + if ((pzval = zend_hash_str_find_deref(Z_ARRVAL_P(pref), "line-break-chars", sizeof("line-break-chars") - 1)) != NULL) { if (Z_TYPE_P(pzval) != IS_STRING) { tmp_str = zval_get_string_func(pzval); + if (EG(exception)) { + return; + } lfchars = ZSTR_VAL(tmp_str); } else { lfchars = Z_STRVAL_P(pzval); diff --git a/ext/imap/php_imap.c b/ext/imap/php_imap.c index 3cee4e023e..b5f12f6eee 100644 --- a/ext/imap/php_imap.c +++ b/ext/imap/php_imap.c @@ -2060,7 +2060,9 @@ PHP_FUNCTION(imap_delete) RETURN_FALSE; } - convert_to_string_ex(sequence); + if (!try_convert_to_string(sequence)) { + return; + } mail_setflag_full(imap_le_struct->imap_stream, Z_STRVAL_P(sequence), "\\DELETED", (argc == 3 ? flags : NIL)); RETVAL_TRUE; @@ -2084,7 +2086,9 @@ PHP_FUNCTION(imap_undelete) RETURN_FALSE; } - convert_to_string_ex(sequence); + if (!try_convert_to_string(sequence)) { + return; + } mail_clearflag_full(imap_le_struct->imap_stream, Z_STRVAL_P(sequence), "\\DELETED", (argc == 3 ? flags : NIL)); RETVAL_TRUE; @@ -2503,7 +2507,9 @@ PHP_FUNCTION(imap_savebody) break; default: - convert_to_string_ex(out); + if (!try_convert_to_string(out)) { + return; + } writer = php_stream_open_wrapper(Z_STRVAL_P(out), "wb", REPORT_ERRORS, NULL); break; } diff --git a/ext/intl/dateformat/dateformat_format_object.cpp b/ext/intl/dateformat/dateformat_format_object.cpp index c2429fb592..90e148bca0 100644 --- a/ext/intl/dateformat/dateformat_format_object.cpp +++ b/ext/intl/dateformat/dateformat_format_object.cpp @@ -142,7 +142,9 @@ U_CFUNC PHP_FUNCTION(datefmt_format_object) } dateStyle = timeStyle = (DateFormat::EStyle)Z_LVAL_P(format); } else { - convert_to_string_ex(format); + if (!try_convert_to_string(format)) { + return; + } if (Z_STRLEN_P(format) == 0) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format_object: the format is empty", 0); diff --git a/ext/intl/timezone/timezone_class.cpp b/ext/intl/timezone/timezone_class.cpp index aabb0f3f55..695cc7d3ea 100644 --- a/ext/intl/timezone/timezone_class.cpp +++ b/ext/intl/timezone/timezone_class.cpp @@ -179,7 +179,10 @@ U_CFUNC TimeZone *timezone_process_timezone_argument(zval *zv_timezone, UnicodeString id, gottenId; UErrorCode status = U_ZERO_ERROR; /* outside_error may be NULL */ - convert_to_string_ex(zv_timezone); + if (!try_convert_to_string(zv_timezone)) { + zval_ptr_dtor_str(&local_zv_tz); + return NULL; + } if (intl_stringFromChar(id, Z_STRVAL_P(zv_timezone), Z_STRLEN_P(zv_timezone), &status) == FAILURE) { spprintf(&message, 0, "%s: Time zone identifier given is not a " diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp index 3f91db3130..6e1d22324b 100644 --- a/ext/intl/timezone/timezone_methods.cpp +++ b/ext/intl/timezone/timezone_methods.cpp @@ -177,7 +177,9 @@ double_offset: } else if (Z_TYPE_P(arg) == IS_OBJECT || Z_TYPE_P(arg) == IS_STRING) { zend_long lval; double dval; - convert_to_string_ex(arg); + if (!try_convert_to_string(arg)) { + return; + } switch (is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), &lval, &dval, 0)) { case IS_DOUBLE: zval_ptr_dtor(arg); diff --git a/ext/intl/transliterator/transliterator_class.c b/ext/intl/transliterator/transliterator_class.c index a662dcee7d..a619ed4309 100644 --- a/ext/intl/transliterator/transliterator_class.c +++ b/ext/intl/transliterator/transliterator_class.c @@ -189,7 +189,7 @@ err: } /* }}} */ -#define TRANSLITERATOR_PROPERTY_HANDLER_PROLOG \ +#define TRANSLITERATOR_PROPERTY_HANDLER_PROLOG(return_fail) \ zval tmp_member; \ if( Z_TYPE_P( member ) != IS_STRING ) \ { \ @@ -197,6 +197,7 @@ err: zval_get_string_func(member)); \ member = &tmp_member; \ cache_slot = NULL; \ + if (EG(exception)) { return_fail; } \ } #define TRANSLITERATOR_PROPERTY_HANDLER_EPILOG \ @@ -210,7 +211,7 @@ static zval *Transliterator_get_property_ptr_ptr( zval *object, zval *member, in { zval *retval; - TRANSLITERATOR_PROPERTY_HANDLER_PROLOG; + TRANSLITERATOR_PROPERTY_HANDLER_PROLOG(return NULL); if(zend_binary_strcmp( "id", sizeof( "id" ) - 1, Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 ) @@ -233,7 +234,7 @@ static zval *Transliterator_read_property( zval *object, zval *member, int type, { zval *retval; - TRANSLITERATOR_PROPERTY_HANDLER_PROLOG; + TRANSLITERATOR_PROPERTY_HANDLER_PROLOG(return &EG(uninitialized_zval)); if( ( type != BP_VAR_R && type != BP_VAR_IS ) && ( zend_binary_strcmp( "id", sizeof( "id" ) - 1, @@ -258,7 +259,7 @@ static zval *Transliterator_read_property( zval *object, zval *member, int type, static zval *Transliterator_write_property( zval *object, zval *member, zval *value, void **cache_slot ) { zend_class_entry *scope; - TRANSLITERATOR_PROPERTY_HANDLER_PROLOG; + TRANSLITERATOR_PROPERTY_HANDLER_PROLOG(return value); if (EG(fake_scope)) { scope = EG(fake_scope); diff --git a/ext/intl/transliterator/transliterator_methods.c b/ext/intl/transliterator/transliterator_methods.c index 25d0b9a4da..50dd344671 100644 --- a/ext/intl/transliterator/transliterator_methods.c +++ b/ext/intl/transliterator/transliterator_methods.c @@ -330,9 +330,8 @@ PHP_FUNCTION( transliterator_transliterate ) else { /* not a transliterator object as first argument */ int res; - if(Z_TYPE_P( arg1 ) != IS_STRING ) - { - convert_to_string( arg1 ); + if( !try_convert_to_string( arg1 ) ) { + return; } object = &tmp_object; res = create_transliterator( Z_STRVAL_P( arg1 ), Z_STRLEN_P( arg1 ), diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 7471065494..15ef274ee4 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -662,8 +662,9 @@ is_string: } } else if (Z_TYPE(retval) != IS_NULL) { /* retval not string nor resource nor null; convert to string */ - convert_to_string(&retval); - goto is_string; + if (try_convert_to_string(&retval)) { + goto is_string; + } } /* else is null; don't try anything */ } diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 69d5fa9101..e3611562e5 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -826,8 +826,13 @@ php_mb_parse_encoding_array(zval *array, const mbfl_encoding ***return_list, siz bauto = 0; n = 0; ZEND_HASH_FOREACH_VAL(target_hash, hash_entry) { - convert_to_string_ex(hash_entry); - if (strcasecmp(Z_STRVAL_P(hash_entry), "auto") == 0) { + zend_string *encoding_str = zval_get_string(hash_entry); + if (EG(exception)) { + ret = FAILURE; + break; + } + + if (strcasecmp(ZSTR_VAL(encoding_str), "auto") == 0) { if (!bauto) { const enum mbfl_no_encoding *src = MBSTRG(default_detect_order_list); const size_t identify_list_size = MBSTRG(default_detect_order_list_size); @@ -840,7 +845,7 @@ php_mb_parse_encoding_array(zval *array, const mbfl_encoding ***return_list, siz } } } else { - const mbfl_encoding *encoding = mbfl_name2encoding(Z_STRVAL_P(hash_entry)); + const mbfl_encoding *encoding = mbfl_name2encoding(ZSTR_VAL(encoding_str)); if (encoding) { *entry++ = encoding; n++; @@ -849,6 +854,7 @@ php_mb_parse_encoding_array(zval *array, const mbfl_encoding ***return_list, siz } } i--; + zend_string_release(encoding_str); } ZEND_HASH_FOREACH_END(); if (n > 0) { if (return_list) { @@ -2000,7 +2006,9 @@ PHP_FUNCTION(mb_detect_order) } break; default: - convert_to_string_ex(arg1); + if (!try_convert_to_string(arg1)) { + return; + } if (FAILURE == php_mb_parse_encoding_list(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), &list, &size, 0)) { if (list) { efree(list); @@ -3328,7 +3336,9 @@ PHP_FUNCTION(mb_convert_encoding) } if (Z_TYPE_P(input) != IS_STRING && Z_TYPE_P(input) != IS_ARRAY) { - convert_to_string(input); + if (!try_convert_to_string(input)) { + return; + } } if (arg_old) { @@ -3338,8 +3348,13 @@ PHP_FUNCTION(mb_convert_encoding) _from_encodings = NULL; ZEND_HASH_FOREACH_VAL(target_hash, hash_entry) { - - convert_to_string_ex(hash_entry); + zend_string *encoding_str = zval_get_string(hash_entry); + if (EG(exception)) { + if (_from_encodings) { + efree(_from_encodings); + } + return; + } if ( _from_encodings) { l = strlen(_from_encodings); @@ -3350,6 +3365,7 @@ PHP_FUNCTION(mb_convert_encoding) } else { _from_encodings = estrdup(Z_STRVAL_P(hash_entry)); } + zend_string_release(encoding_str); } ZEND_HASH_FOREACH_END(); if (_from_encodings != NULL && !strlen(_from_encodings)) { @@ -3359,7 +3375,10 @@ PHP_FUNCTION(mb_convert_encoding) s_free = _from_encodings; break; default: - convert_to_string(arg_old); + if (!try_convert_to_string(arg_old)) { + return; + } + _from_encodings = Z_STRVAL_P(arg_old); break; } @@ -3535,7 +3554,9 @@ PHP_FUNCTION(mb_detect_encoding) } break; default: - convert_to_string(encoding_list); + if (!try_convert_to_string(encoding_list)) { + return; + } if (FAILURE == php_mb_parse_encoding_list(Z_STRVAL_P(encoding_list), Z_STRLEN_P(encoding_list), &list, &size, 0)) { if (list) { efree(list); @@ -3944,7 +3965,9 @@ PHP_FUNCTION(mb_convert_variables) php_mb_parse_encoding_array(zfrom_enc, &elist, &elistsz, 0); break; default: - convert_to_string_ex(zfrom_enc); + if (!try_convert_to_string(zfrom_enc)) { + return; + } php_mb_parse_encoding_list(Z_STRVAL_P(zfrom_enc), Z_STRLEN_P(zfrom_enc), &elist, &elistsz, 0); break; } diff --git a/ext/mbstring/php_mbregex.c b/ext/mbstring/php_mbregex.c index 83cd25d89d..9fac8233ba 100644 --- a/ext/mbstring/php_mbregex.c +++ b/ext/mbstring/php_mbregex.c @@ -924,7 +924,9 @@ static void _php_mb_regex_ereg_exec(INTERNAL_FUNCTION_PARAMETERS, int icase) if (Z_TYPE_P(arg_pattern) == IS_DOUBLE) { convert_to_long_ex(arg_pattern); /* get rid of decimal places */ } - convert_to_string_ex(arg_pattern); + if (!try_convert_to_string(arg_pattern)) { + return; + } /* don't bother doing an extended regex with just a number */ } diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index 394a838512..9964ea0be4 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -309,6 +309,9 @@ zval *mysqli_read_property(zval *object, zval *member, int type, void **cache_sl if (Z_TYPE_P(member) != IS_STRING) { ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; + if (EG(exception)) { + return &EG(uninitialized_zval); + } } if (obj->prop_handler != NULL) { @@ -342,6 +345,9 @@ zval *mysqli_write_property(zval *object, zval *member, zval *value, void **cach if (Z_TYPE_P(member) != IS_STRING) { ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; + if (EG(exception)) { + return value; + } } obj = Z_MYSQLI_P(object); diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 1a7303c987..13d21e9312 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -899,7 +899,10 @@ PHP_FUNCTION(mysqli_stmt_execute) if (!(stmt->param.is_null[i] = (Z_ISNULL_P(param)))) { switch (stmt->stmt->params[i].buffer_type) { case MYSQL_TYPE_VAR_STRING: - convert_to_string_ex(param); + if (!try_convert_to_string(param)) { + return; + } + stmt->stmt->params[i].buffer = Z_STRVAL_P(param); stmt->stmt->params[i].buffer_length = Z_STRLEN_P(param); break; @@ -1781,7 +1784,9 @@ PHP_FUNCTION(mysqli_options) if (expected_type != Z_TYPE_P(mysql_value)) { switch (expected_type) { case IS_STRING: - convert_to_string_ex(mysql_value); + if (!try_convert_to_string(mysql_value)) { + return; + } break; case IS_LONG: convert_to_long_ex(mysql_value); diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c index 641c7ee783..7da46a90f8 100644 --- a/ext/mysqlnd/mysqlnd_ps_codec.c +++ b/ext/mysqlnd/mysqlnd_ps_codec.c @@ -777,7 +777,10 @@ use_string: } the_var = &((*copies_param)[i]); } - convert_to_string_ex(the_var); + + if (!try_convert_to_string(the_var)) { + goto end; + } *data_size += Z_STRLEN_P(the_var); break; } diff --git a/ext/oci8/oci8_statement.c b/ext/oci8/oci8_statement.c index 4face29e4a..91f6223373 100644 --- a/ext/oci8/oci8_statement.c +++ b/ext/oci8/oci8_statement.c @@ -1189,7 +1189,9 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l return 1; } if (Z_TYPE_P(param) != IS_NULL) { - convert_to_string(param); + if (!try_convert_to_string(param)) { + return 1; + } } if ((maxlength == -1) || (maxlength == 0)) { if (type == SQLT_LNG) { @@ -1390,8 +1392,10 @@ sb4 php_oci_bind_in_callback( *alenp = -1; *indpp = (dvoid *)&phpbind->indicator; } else if ((phpbind->descriptor == 0) && (phpbind->statement == 0)) { - /* "normal string bind */ - convert_to_string(val); + /* "normal" string bind */ + if (!try_convert_to_string(val)) { + return OCI_ERROR; + } *bufpp = Z_STRVAL_P(val); *alenp = (ub4) Z_STRLEN_P(val); @@ -1483,7 +1487,6 @@ sb4 php_oci_bind_out_callback( *indpp = &phpbind->indicator; retval = OCI_CONTINUE; } else { - convert_to_string(val); zval_ptr_dtor(val); { @@ -1741,7 +1744,9 @@ php_oci_bind *php_oci_bind_array_helper_string(zval *var, zend_long max_table_le if (maxlength == -1) { zend_hash_internal_pointer_reset(hash); while ((entry = zend_hash_get_current_data(hash)) != NULL) { - convert_to_string_ex(entry); + if (!try_convert_to_string(entry)) { + return NULL; + } if (maxlength == -1 || Z_STRLEN_P(entry) > (size_t) maxlength) { maxlength = Z_STRLEN_P(entry) + 1; @@ -1767,7 +1772,14 @@ php_oci_bind *php_oci_bind_array_helper_string(zval *var, zend_long max_table_le for (i = 0; i < bind->array.current_length; i++) { if ((entry = zend_hash_get_current_data(hash)) != NULL) { - convert_to_string_ex(entry); + if (!try_convert_to_string(entry)) { + efree(bind->array.elements); + efree(bind->array.element_lengths); + efree(bind->array.indicators); + efree(bind); + return NULL; + } + bind->array.element_lengths[i] = (ub2) Z_STRLEN_P(entry); if (Z_STRLEN_P(entry) == 0) { bind->array.indicators[i] = -1; @@ -1782,8 +1794,14 @@ php_oci_bind *php_oci_bind_array_helper_string(zval *var, zend_long max_table_le for (i = 0; i < max_table_length; i++) { if ((i < bind->array.current_length) && (entry = zend_hash_get_current_data(hash)) != NULL) { int element_length; + if (!try_convert_to_string(entry)) { + efree(bind->array.elements); + efree(bind->array.element_lengths); + efree(bind->array.indicators); + efree(bind); + return NULL; + } - convert_to_string_ex(entry); element_length = ((size_t) maxlength > Z_STRLEN_P(entry)) ? (int) Z_STRLEN_P(entry) : (int) maxlength; memcpy((text *)bind->array.elements + i*maxlength, Z_STRVAL_P(entry), element_length); @@ -1912,9 +1930,16 @@ php_oci_bind *php_oci_bind_array_helper_date(zval *var, zend_long max_table_leng bind->array.element_lengths[i] = sizeof(OCIDate); } if ((i < bind->array.current_length) && (entry = zend_hash_get_current_data(hash)) != NULL) { + zend_string *entry_str = zval_get_string(entry); + if (EG(exception)) { + efree(bind->array.element_lengths); + efree(bind->array.elements); + efree(bind); + return NULL; + } - convert_to_string_ex(entry); - PHP_OCI_CALL_RETURN(errstatus, OCIDateFromText, (connection->err, (CONST text *)Z_STRVAL_P(entry), (ub4) Z_STRLEN_P(entry), NULL, 0, NULL, 0, &oci_date)); + PHP_OCI_CALL_RETURN(errstatus, OCIDateFromText, (connection->err, (CONST text *)ZSTR_VAL(entry_str), (ub4) ZSTR_LEN(entry_str), NULL, 0, NULL, 0, &oci_date)); + zend_string_release(entry_str); if (errstatus != OCI_SUCCESS) { /* failed to convert string to date */ diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 37257c3e12..6bd24781b4 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -1343,9 +1343,7 @@ PHP_FUNCTION(odbc_execute) } otype = Z_TYPE_P(tmp); - convert_to_string_ex(tmp); - if (Z_TYPE_P(tmp) != IS_STRING) { - php_error_docref(NULL, E_WARNING,"Error converting parameter"); + if (!try_convert_to_string(tmp)) { SQLFreeStmt(result->stmt, SQL_RESET_PARAMS); for (i = 0; i < result->numparams; i++) { if (params[i].fp != -1) { diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 8cf294b361..7f287c8823 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1725,7 +1725,9 @@ static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_reso } /* force it to be a string and check if it refers to a file */ - convert_to_string_ex(val); + if (!try_convert_to_string(val)) { + return NULL; + } if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) { @@ -2671,32 +2673,37 @@ static X509_STORE *php_openssl_setup_verify(zval *calist) if (calist && (Z_TYPE_P(calist) == IS_ARRAY)) { ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(calist), item) { - convert_to_string_ex(item); + zend_string *str = zval_get_string(item); + if (EG(exception)) { + return NULL; + } - if (VCWD_STAT(Z_STRVAL_P(item), &sb) == -1) { - php_error_docref(NULL, E_WARNING, "unable to stat %s", Z_STRVAL_P(item)); + if (VCWD_STAT(ZSTR_VAL(str), &sb) == -1) { + php_error_docref(NULL, E_WARNING, "unable to stat %s", ZSTR_VAL(str)); + zend_string_release(str); continue; } if ((sb.st_mode & S_IFREG) == S_IFREG) { file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); - if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, Z_STRVAL_P(item), X509_FILETYPE_PEM)) { + if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, ZSTR_VAL(str), X509_FILETYPE_PEM)) { php_openssl_store_errors(); - php_error_docref(NULL, E_WARNING, "error loading file %s", Z_STRVAL_P(item)); + php_error_docref(NULL, E_WARNING, "error loading file %s", ZSTR_VAL(str)); } else { nfiles++; } file_lookup = NULL; } else { dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); - if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, Z_STRVAL_P(item), X509_FILETYPE_PEM)) { + if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, ZSTR_VAL(str), X509_FILETYPE_PEM)) { php_openssl_store_errors(); - php_error_docref(NULL, E_WARNING, "error loading directory %s", Z_STRVAL_P(item)); + php_error_docref(NULL, E_WARNING, "error loading directory %s", ZSTR_VAL(str)); } else { ndirs++; } dir_lookup = NULL; } + zend_string_release(str); } ZEND_HASH_FOREACH_END(); } if (nfiles == 0) { @@ -3145,23 +3152,25 @@ static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, z /* apply values from the dn hash */ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(dn), strindex, item) { if (strindex) { - int nid; - - convert_to_string_ex(item); - - nid = OBJ_txt2nid(ZSTR_VAL(strindex)); + int nid = OBJ_txt2nid(ZSTR_VAL(strindex)); if (nid != NID_undef) { + zend_string *str_item = zval_get_string(item); + if (EG(exception)) { + return FAILURE; + } if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, - (unsigned char*)Z_STRVAL_P(item), -1, -1, 0)) + (unsigned char*)ZSTR_VAL(str_item), -1, -1, 0)) { php_openssl_store_errors(); php_error_docref(NULL, E_WARNING, "dn: add_entry_by_NID %d -> %s (failed; check error" " queue and value of string_mask OpenSSL option " "if illegal characters are reported)", - nid, Z_STRVAL_P(item)); + nid, ZSTR_VAL(str_item)); + zend_string_release(str_item); return FAILURE; } + zend_string_release(str_item); } else { php_error_docref(NULL, E_WARNING, "dn: %s is not a recognized name", ZSTR_VAL(strindex)); } @@ -3226,15 +3235,19 @@ static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, z continue; } - convert_to_string_ex(item); - nid = OBJ_txt2nid(ZSTR_VAL(strindex)); if (nid != NID_undef) { - if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, (unsigned char*)Z_STRVAL_P(item), -1, -1, 0)) { + zend_string *str_item = zval_get_string(item); + if (EG(exception)) { + return FAILURE; + } + if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, (unsigned char*)ZSTR_VAL(str_item), -1, -1, 0)) { php_openssl_store_errors(); - php_error_docref(NULL, E_WARNING, "attribs: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_P(item)); + php_error_docref(NULL, E_WARNING, "attribs: add_entry_by_NID %d -> %s (failed)", nid, ZSTR_VAL(str_item)); + zend_string_release(str_item); return FAILURE; } + zend_string_release(str_item); } else { php_error_docref(NULL, E_WARNING, "dn: %s is not a recognized name", ZSTR_VAL(strindex)); } @@ -3803,7 +3816,10 @@ static EVP_PKEY * php_openssl_evp_from_zval( passphrase_len = Z_STRLEN_P(zphrase); } else { ZVAL_COPY(&tmp, zphrase); - convert_to_string(&tmp); + if (!try_convert_to_string(&tmp)) { + return NULL; + } + passphrase = Z_STRVAL(tmp); passphrase_len = Z_STRLEN(tmp); } @@ -3864,7 +3880,9 @@ static EVP_PKEY * php_openssl_evp_from_zval( if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) { TMP_CLEAN; } - convert_to_string_ex(val); + if (!try_convert_to_string(val)) { + TMP_CLEAN; + } if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) { filename = Z_STRVAL_P(val) + (sizeof("file://") - 1); @@ -5351,13 +5369,16 @@ PHP_FUNCTION(openssl_pkcs7_encrypt) /* tack on extra headers */ if (zheaders) { ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, zcertval) { - convert_to_string_ex(zcertval); - + zend_string *str = zval_get_string(zcertval); + if (EG(exception)) { + goto clean_exit; + } if (strindex) { - BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(zcertval)); + BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), ZSTR_VAL(str)); } else { - BIO_printf(outfile, "%s\n", Z_STRVAL_P(zcertval)); + BIO_printf(outfile, "%s\n", ZSTR_VAL(str)); } + zend_string_release(str); } ZEND_HASH_FOREACH_END(); } @@ -5566,13 +5587,16 @@ PHP_FUNCTION(openssl_pkcs7_sign) int ret; ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, hval) { - convert_to_string_ex(hval); - + zend_string *str = zval_get_string(hval); + if (EG(exception)) { + goto clean_exit; + } if (strindex) { - ret = BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(hval)); + ret = BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), ZSTR_VAL(str)); } else { - ret = BIO_printf(outfile, "%s\n", Z_STRVAL_P(hval)); + ret = BIO_printf(outfile, "%s\n", ZSTR_VAL(str)); } + zend_string_release(str); if (ret < 0) { php_openssl_store_errors(); } diff --git a/ext/openssl/tests/bug38261.phpt b/ext/openssl/tests/bug38261.phpt index fa25d93d62..e6e345d5ea 100644 --- a/ext/openssl/tests/bug38261.phpt +++ b/ext/openssl/tests/bug38261.phpt @@ -19,7 +19,11 @@ var_dump(openssl_x509_parse($t)); var_dump(openssl_x509_parse(array())); var_dump(openssl_x509_parse()); var_dump(openssl_x509_parse($cert)); -var_dump(openssl_x509_parse(new stdClass)); +try { + var_dump(openssl_x509_parse(new stdClass)); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} ?> --EXPECTF-- @@ -30,5 +34,4 @@ bool(false) Warning: openssl_x509_parse() expects at least 1 parameter, 0 given in %sbug38261.php on line %d NULL bool(false) - -Recoverable fatal error: Object of class stdClass could not be converted to string in %sbug38261.php on line %d +Object of class stdClass could not be converted to string diff --git a/ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt b/ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt index f892c6854f..63dabe8f32 100644 --- a/ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt +++ b/ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt @@ -15,7 +15,11 @@ $b = 1; $c = new stdclass; $d = new stdclass; -var_dump(openssl_pkcs7_decrypt($a, $b, $c, $d)); +try { + var_dump(openssl_pkcs7_decrypt($a, $b, $c, $d)); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} var_dump($c); var_dump(openssl_pkcs7_decrypt($b, $b, $b, $b)); @@ -26,9 +30,7 @@ var_dump(openssl_pkcs7_decrypt($a, $b, 0, 0)); echo "Done\n"; ?> --EXPECT-- -string(57) "Object of class stdClass could not be converted to string" -string(66) "openssl_pkcs7_decrypt(): unable to coerce parameter 3 to x509 cert" -bool(false) +Object of class stdClass could not be converted to string object(stdClass)#1 (0) { } string(66) "openssl_pkcs7_decrypt(): unable to coerce parameter 3 to x509 cert" diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index d5276cd5b9..ad08e1f13a 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -97,7 +97,9 @@ #define GET_VER_OPT(name) \ (PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", name)) != NULL) #define GET_VER_OPT_STRING(name, str) \ - if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_P(val); } + if (GET_VER_OPT(name)) { \ + if (try_convert_to_string(val)) str = Z_STRVAL_P(val); \ + } #define GET_VER_OPT_LONG(name, num) \ if (GET_VER_OPT(name)) { num = zval_get_long(val); } @@ -1251,7 +1253,10 @@ static int php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX *ctx) /* return SUCCESS; } - convert_to_string_ex(zdhpath); + if (!try_convert_to_string(zdhpath)) { + return FAILURE; + } + bio = BIO_new_file(Z_STRVAL_P(zdhpath), PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); if (bio == NULL) { @@ -1295,7 +1300,10 @@ static int php_openssl_set_server_ecdh_curve(php_stream *stream, SSL_CTX *ctx) / curve_nid = NID_X9_62_prime256v1; #endif } else { - convert_to_string_ex(zvcurve); + if (!try_convert_to_string(zvcurve)) { + return FAILURE; + } + curve_nid = OBJ_sn2nid(Z_STRVAL_P(zvcurve)); if (curve_nid == NID_undef) { php_error_docref(NULL, E_WARNING, "invalid ecdh_curve specified"); @@ -1465,6 +1473,7 @@ static int php_openssl_enable_server_sni(php_stream *stream, php_openssl_netstre if (Z_TYPE_P(current) == IS_ARRAY) { zval *local_pk, *local_cert; + zend_string *local_pk_str, *local_cert_str; char resolved_cert_path_buff[MAXPATHLEN], resolved_pk_path_buff[MAXPATHLEN]; local_cert = zend_hash_str_find(Z_ARRVAL_P(current), "local_cert", sizeof("local_cert")-1); @@ -1474,14 +1483,21 @@ static int php_openssl_enable_server_sni(php_stream *stream, php_openssl_netstre ); return FAILURE; } - convert_to_string_ex(local_cert); - if (!VCWD_REALPATH(Z_STRVAL_P(local_cert), resolved_cert_path_buff)) { + + local_cert_str = zval_get_string(local_cert); + if (EG(exception)) { + return FAILURE; + } + if (!VCWD_REALPATH(ZSTR_VAL(local_cert_str), resolved_cert_path_buff)) { php_error_docref(NULL, E_WARNING, "failed setting local cert chain file `%s'; file not found", - Z_STRVAL_P(local_cert) + ZSTR_VAL(local_cert_str) ); + zend_string_release(local_cert_str); return FAILURE; } + zend_string_release(local_cert_str); + local_pk = zend_hash_str_find(Z_ARRVAL_P(current), "local_pk", sizeof("local_pk")-1); if (local_pk == NULL) { php_error_docref(NULL, E_WARNING, @@ -1489,14 +1505,20 @@ static int php_openssl_enable_server_sni(php_stream *stream, php_openssl_netstre ); return FAILURE; } - convert_to_string_ex(local_pk); - if (!VCWD_REALPATH(Z_STRVAL_P(local_pk), resolved_pk_path_buff)) { + + local_pk_str = zval_get_string(local_pk); + if (EG(exception)) { + return FAILURE; + } + if (!VCWD_REALPATH(ZSTR_VAL(local_pk_str), resolved_pk_path_buff)) { php_error_docref(NULL, E_WARNING, "failed setting local private key file `%s'; file not found", - Z_STRVAL_P(local_pk) + ZSTR_VAL(local_pk_str) ); + zend_string_release(local_pk_str); return FAILURE; } + zend_string_release(local_pk_str); ctx = php_openssl_create_sni_server_ctx(resolved_cert_path_buff, resolved_pk_path_buff); diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 63751d4b17..300de1e7d4 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -967,6 +967,7 @@ PHP_FUNCTION(pcntl_exec) if (ZEND_NUM_ARGS() > 1) { /* Build argument list */ + SEPARATE_ARRAY(args); args_hash = Z_ARRVAL_P(args); argc = zend_hash_num_elements(args_hash); @@ -975,20 +976,25 @@ PHP_FUNCTION(pcntl_exec) current_arg = argv+1; ZEND_HASH_FOREACH_VAL(args_hash, element) { if (argi >= argc) break; - convert_to_string_ex(element); + if (!try_convert_to_string(element)) { + efree(argv); + return; + } + *current_arg = Z_STRVAL_P(element); argi++; current_arg++; } ZEND_HASH_FOREACH_END(); - *(current_arg) = NULL; + *current_arg = NULL; } else { argv = emalloc(2 * sizeof(char *)); - *argv = path; - *(argv+1) = NULL; + argv[0] = path; + argv[1] = NULL; } if ( ZEND_NUM_ARGS() == 3 ) { /* Build environment pair list */ + SEPARATE_ARRAY(envs); envs_hash = Z_ARRVAL_P(envs); envc = zend_hash_num_elements(envs_hash); @@ -1001,7 +1007,12 @@ PHP_FUNCTION(pcntl_exec) zend_string_addref(key); } - convert_to_string_ex(element); + if (!try_convert_to_string(element)) { + zend_string_release(key); + efree(argv); + efree(envp); + return; + } /* Length of element + equal sign + length of key + null */ pair_length = Z_STRLEN_P(element) + ZSTR_LEN(key) + 2; diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 05f8d9f817..46794fe1d1 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1529,6 +1529,11 @@ PHPAPI zend_string *php_pcre_replace(zend_string *regex, pcre_cache_entry *pce; /* Compiled regular expression */ zend_string *result; /* Function result */ + /* Abort on pending exception, e.g. thrown from __toString(). */ + if (UNEXPECTED(EG(exception))) { + return NULL; + } + /* Compile regex or get it from cache. */ if ((pce = pcre_get_compiled_regex_cache(regex)) == NULL) { return NULL; diff --git a/ext/pcre/tests/preg_replace_error1.phpt b/ext/pcre/tests/preg_replace_error1.phpt index 8e20108b88..780556956a 100644 --- a/ext/pcre/tests/preg_replace_error1.phpt +++ b/ext/pcre/tests/preg_replace_error1.phpt @@ -24,7 +24,11 @@ foreach($regex_array as $regex_value) { var_dump(preg_replace($regex_value, $replace, $subject)); } $regex_value = new stdclass(); //Object -var_dump(preg_replace($regex_value, $replace, $subject)); +try { + var_dump(preg_replace($regex_value, $replace, $subject)); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} ?> --EXPECTF-- *** Testing preg_replace() : error conditions*** @@ -54,5 +58,4 @@ string(1) "a" Arg value is /[a-zA-Z]/ string(1) "1" - -Recoverable fatal error: Object of class stdClass could not be converted to string in %spreg_replace_error1.php on line %d +Object of class stdClass could not be converted to string diff --git a/ext/pcre/tests/preg_replace_error2.phpt b/ext/pcre/tests/preg_replace_error2.phpt index 8c826587ea..a334b2fefd 100644 --- a/ext/pcre/tests/preg_replace_error2.phpt +++ b/ext/pcre/tests/preg_replace_error2.phpt @@ -19,7 +19,11 @@ foreach($replace as $value) { var_dump(preg_replace($regex, $value, $subject)); } $value = new stdclass(); //Object -var_dump(preg_replace($regex, $value, $subject)); +try { + var_dump(preg_replace($regex, $value, $subject)); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} echo "Done"; ?> --EXPECTF-- @@ -32,5 +36,5 @@ Arg value is: Array Warning: preg_replace(): Parameter mismatch, pattern is a string while replacement is an array in %spreg_replace_error2.php on line %d bool(false) - -Recoverable fatal error: Object of class stdClass could not be converted to string in %spreg_replace_error2.php on line %d +Object of class stdClass could not be converted to string +Done diff --git a/ext/pdo/pdo_sql_parser.re b/ext/pdo/pdo_sql_parser.re index 5950cdc38e..b04e2fb928 100644 --- a/ext/pdo/pdo_sql_parser.re +++ b/ext/pdo/pdo_sql_parser.re @@ -269,7 +269,8 @@ safe: default: buf = zval_get_string(parameter); - if (!stmt->dbh->methods->quoter(stmt->dbh, ZSTR_VAL(buf), + if (EG(exception) || + !stmt->dbh->methods->quoter(stmt->dbh, ZSTR_VAL(buf), ZSTR_LEN(buf), &plc->quoted, &plc->qlen, param_type)) { /* bork */ diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 92e594c76b..bd93ca3cb2 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -307,7 +307,9 @@ static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_s ZVAL_STRINGL(parameter, p, len); efree(p); } else { - convert_to_string(parameter); + if (!try_convert_to_string(parameter)) { + return 0; + } } } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && (Z_TYPE_P(parameter) == IS_FALSE || Z_TYPE_P(parameter) == IS_TRUE)) { convert_to_long(parameter); @@ -911,7 +913,9 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, enum pdo_ fetch_value(stmt, &val, i++, NULL); if (Z_TYPE(val) != IS_NULL) { - convert_to_string(&val); + if (!try_convert_to_string(&val)) { + return 0; + } if ((cep = zend_lookup_class(Z_STR(val))) == NULL) { stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR; } else { @@ -2180,7 +2184,9 @@ static zval *dbstmt_prop_write(zval *object, zval *member, zval *value, void **c { pdo_stmt_t *stmt = Z_PDO_STMT_P(object); - convert_to_string(member); + if (!try_convert_to_string(member)) { + return value; + } if (strcmp(Z_STRVAL_P(member), "queryString") == 0) { pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only"); @@ -2194,7 +2200,9 @@ static void dbstmt_prop_delete(zval *object, zval *member, void **cache_slot) { pdo_stmt_t *stmt = Z_PDO_STMT_P(object); - convert_to_string(member); + if (!try_convert_to_string(member)) { + return; + } if (strcmp(Z_STRVAL_P(member), "queryString") == 0) { pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only"); @@ -2459,7 +2467,10 @@ static zval *row_prop_read(zval *object, zval *member, int type, void **cache_sl fetch_value(stmt, rv, lval, NULL); } } else { - convert_to_string(member); + if (!try_convert_to_string(member)) { + return &EG(uninitialized_zval); + } + /* TODO: replace this with a hash of available column names to column * numbers */ for (colno = 0; colno < stmt->column_count; colno++) { @@ -2511,7 +2522,9 @@ static int row_prop_exists(zval *object, zval *member, int check_empty, void **c return lval >=0 && lval < stmt->column_count; } } else { - convert_to_string(member); + if (!try_convert_to_string(member)) { + return 0; + } } /* TODO: replace this with a hash of available column names to column diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index d17b168c2d..d057857fa6 100644 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -215,7 +215,7 @@ static inline zend_string *pdo_attr_strval(zval *options, enum pdo_attribute_typ zval *v; if (options && (v = zend_hash_index_find(Z_ARRVAL_P(options), option_name))) { - return zval_get_string(v); + return zval_try_get_string(v); } return defval ? zend_string_copy(defval) : NULL; } diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index 6c83717e65..a4ff7e5c5a 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -466,6 +466,9 @@ static int firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *v case PDO_FB_ATTR_DATE_FORMAT: { zend_string *str = zval_get_string(val); + if (EG(exception)) { + return 0; + } if (H->date_format) { efree(H->date_format); } @@ -477,6 +480,9 @@ static int firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *v case PDO_FB_ATTR_TIME_FORMAT: { zend_string *str = zval_get_string(val); + if (EG(exception)) { + return 0; + } if (H->time_format) { efree(H->time_format); } @@ -488,6 +494,9 @@ static int firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *v case PDO_FB_ATTR_TIMESTAMP_FORMAT: { zend_string *str = zval_get_string(val); + if (EG(exception)) { + return 0; + } if (H->timestamp_format) { efree(H->timestamp_format); } diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c index af71007b56..aee748d0e1 100644 --- a/ext/pdo_firebird/firebird_statement.c +++ b/ext/pdo_firebird/firebird_statement.c @@ -728,7 +728,9 @@ static int firebird_stmt_set_attribute(pdo_stmt_t *stmt, zend_long attr, zval *v default: return 0; case PDO_ATTR_CURSOR_NAME: - convert_to_string(val); + if (!try_convert_to_string(val)) { + return 0; + } if (isc_dsql_set_cursor_name(S->H->isc_status, &S->stmt, Z_STRVAL_P(val),0)) { RECORD_ERROR(stmt); diff --git a/ext/pdo_oci/oci_driver.c b/ext/pdo_oci/oci_driver.c index 607069008d..f121b4791b 100644 --- a/ext/pdo_oci/oci_driver.c +++ b/ext/pdo_oci/oci_driver.c @@ -461,6 +461,9 @@ static int oci_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val) / { #if (OCI_MAJOR_VERSION >= 10) zend_string *action = zval_get_string(val); + if (EG(exception)) { + return 0; + } H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION, (dvoid *) ZSTR_VAL(action), (ub4) ZSTR_LEN(action), @@ -479,6 +482,9 @@ static int oci_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val) / { #if (OCI_MAJOR_VERSION >= 10) zend_string *client_info = zval_get_string(val); + if (EG(exception)) { + return 0; + } H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION, (dvoid *) ZSTR_VAL(client_info), (ub4) ZSTR_LEN(client_info), @@ -497,6 +503,9 @@ static int oci_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val) / { #if (OCI_MAJOR_VERSION >= 10) zend_string *identifier = zval_get_string(val); + if (EG(exception)) { + return 0; + } H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION, (dvoid *) ZSTR_VAL(identifier), (ub4) ZSTR_LEN(identifier), @@ -515,6 +524,9 @@ static int oci_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val) / { #if (OCI_MAJOR_VERSION >= 10) zend_string *module = zval_get_string(val); + if (EG(exception)) { + return 0; + } H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION, (dvoid *) ZSTR_VAL(module), (ub4) ZSTR_LEN(module), diff --git a/ext/pdo_oci/oci_statement.c b/ext/pdo_oci/oci_statement.c index 79733c2c57..b983f20116 100644 --- a/ext/pdo_oci/oci_statement.c +++ b/ext/pdo_oci/oci_statement.c @@ -221,7 +221,9 @@ static sb4 oci_bind_input_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dv *alenp = -1; } else if (!P->thing) { /* regular string bind */ - convert_to_string(parameter); + if (!try_convert_to_string(parameter)) { + return OCI_ERROR; + } *bufpp = Z_STRVAL_P(parameter); *alenp = (ub4) Z_STRLEN_P(parameter); } @@ -260,8 +262,7 @@ static sb4 oci_bind_output_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, d return OCI_CONTINUE; } - convert_to_string(parameter); - zval_ptr_dtor_str(parameter); + zval_ptr_dtor(parameter); Z_STR_P(parameter) = zend_string_alloc(param->max_value_len, 1); P->used_for_output = 1; diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index e8b748a36f..5aae5d0a38 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -592,7 +592,10 @@ static PHP_METHOD(PDO, pgsqlCopyFromArray) PQclear(pgsql_result); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), tmp) { size_t query_len; - convert_to_string_ex(tmp); + if (!try_convert_to_string(tmp)) { + efree(query); + return; + } if (buffer_len < Z_STRLEN_P(tmp)) { buffer_len = Z_STRLEN_P(tmp); diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index 02342e9fe4..9e86a82323 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -411,7 +411,10 @@ static int do_callback(struct pdo_sqlite_fci *fc, zval *cb, break; default: - convert_to_string_ex(&retval); + if (!try_convert_to_string(&retval)) { + ret = FAILURE; + break; + } sqlite3_result_text(context, Z_STRVAL(retval), Z_STRLEN(retval), SQLITE_TRANSIENT); break; } diff --git a/ext/pdo_sqlite/sqlite_statement.c b/ext/pdo_sqlite/sqlite_statement.c index 186bf182b1..d8a68efb05 100644 --- a/ext/pdo_sqlite/sqlite_statement.c +++ b/ext/pdo_sqlite/sqlite_statement.c @@ -153,7 +153,9 @@ static int pdo_sqlite_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_d pdo_sqlite_error_stmt(stmt); return 0; } else { - convert_to_string(parameter); + if (!try_convert_to_string(parameter)) { + return 0; + } } if (SQLITE_OK == sqlite3_bind_blob(S->stmt, param->paramno + 1, @@ -176,7 +178,9 @@ static int pdo_sqlite_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_d return 1; } } else { - convert_to_string(parameter); + if (!try_convert_to_string(parameter)) { + return 0; + } if (SQLITE_OK == sqlite3_bind_text(S->stmt, param->paramno + 1, Z_STRVAL_P(parameter), Z_STRLEN_P(parameter), diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_tostring_exception.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_tostring_exception.phpt new file mode 100644 index 0000000000..b1cd78eee7 --- /dev/null +++ b/ext/pdo_sqlite/tests/pdo_sqlite_tostring_exception.phpt @@ -0,0 +1,45 @@ +--TEST-- +__toString() exception during PDO Sqlite parameter binding +--SKIPIF-- +<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?> +--FILE-- +<?php + +class throws { + function __toString() { + throw new Exception("Sorry"); + } +} + +$db = new PDO('sqlite::memory:'); +$db->exec('CREATE TABLE t(id int, v varchar(255))'); + +$stmt = $db->prepare('INSERT INTO t VALUES(:i, :v)'); +$param1 = 1234; +$stmt->bindValue('i', $param1); +$param2 = "foo"; +$stmt->bindParam('v', $param2); + +$param2 = new throws; + +try { + $stmt->execute(); +} catch (Exception $e) { + echo "Exception thrown ...\n"; +} + +try { + $stmt->execute(); +} catch (Exception $e) { + echo "Exception thrown ...\n"; +} + +$query = $db->query("SELECT * FROM t"); +while ($row = $query->fetch(PDO::FETCH_ASSOC)) { + print_r($row); +} + +?> +--EXPECT-- +Exception thrown ... +Exception thrown ... diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 1be592a319..9dd08f249a 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -1330,6 +1330,11 @@ static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) smart_str_appendl(&str, Z_STRVAL(args[i]), Z_STRLEN(args[i])); } + /* Exception thrown during a string conversion. */ + if (EG(exception)) { + goto cleanup; + } + smart_str_0(&str); if (ZEND_NUM_ARGS() == 1) { /* new style, using connection string */ @@ -3045,7 +3050,6 @@ static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) switch (Z_TYPE_P(field)) { case IS_STRING: - convert_to_string_ex(field); field_offset = PQfnumber(pgsql_result, Z_STRVAL_P(field)); if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) { php_error_docref(NULL, E_WARNING, "Bad column offset specified"); @@ -4280,22 +4284,23 @@ PHP_FUNCTION(pg_copy_from) PQclear(pgsql_result); #if HAVE_PQPUTCOPYDATA ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), value) { - zval tmp; - 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); - if(Z_STRLEN(tmp) > 0 && *(query + Z_STRLEN(tmp) - 1) != '\n') { - strlcat(query, "\n", Z_STRLEN(tmp) + 2); + zend_string *tmp = zval_get_string(value); + if (EG(exception)) { + return; + } + query = (char *)emalloc(ZSTR_LEN(tmp) + 2); + strlcpy(query, ZSTR_VAL(tmp), ZSTR_LEN(tmp) + 2); + if (ZSTR_LEN(tmp) > 0 && *(query + ZSTR_LEN(tmp) - 1) != '\n') { + strlcat(query, "\n", ZSTR_LEN(tmp) + 2); } if (PQputCopyData(pgsql, query, (int)strlen(query)) != 1) { efree(query); - zval_ptr_dtor_str(&tmp); + zend_string_release(tmp); PHP_PQ_ERROR("copy failed: %s", pgsql); RETURN_FALSE; } efree(query); - zval_ptr_dtor_str(&tmp); + zend_string_release(tmp); } ZEND_HASH_FOREACH_END(); if (PQputCopyEnd(pgsql, NULL) != 1) { @@ -4304,22 +4309,23 @@ PHP_FUNCTION(pg_copy_from) } #else ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), value) { - zval tmp; - 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); - if(Z_STRLEN(tmp) > 0 && *(query + Z_STRLEN(tmp) - 1) != '\n') { - strlcat(query, "\n", Z_STRLEN(tmp) + 2); + zend_string *tmp = zval_get_string(value); + if (EG(exception)) { + return; + } + query = (char *)emalloc(ZSTR_LEN(tmp) + 2); + strlcpy(query, ZSTR_LVAL(tmp), ZSTR_LEN(tmp) + 2); + if (ZSTR_LEN(tmp) > 0 && *(query + ZSTR_LEN(tmp) - 1) != '\n') { + strlcat(query, "\n", ZSTR_LEN(tmp) + 2); } if (PQputline(pgsql, query)==EOF) { efree(query); - zval_ptr_dtor_str(&tmp); + zend_string_release(tmp); PHP_PQ_ERROR("copy failed: %s", pgsql); RETURN_FALSE; } efree(query); - zval_ptr_dtor_str(&tmp); + zend_string_release(tmp); } ZEND_HASH_FOREACH_END(); if (PQputline(pgsql, "\\.\n") == EOF) { @@ -5167,17 +5173,13 @@ PHP_FUNCTION(pg_send_execute) if (Z_TYPE_P(tmp) == IS_NULL) { params[i] = NULL; } else { - zval tmp_val; - ZVAL_COPY(&tmp_val, tmp); - convert_to_string(&tmp_val); - if (Z_TYPE(tmp_val) != IS_STRING) { - php_error_docref(NULL, E_WARNING,"Error converting parameter"); - zval_ptr_dtor(&tmp_val); + zend_string *tmp_str = zval_get_string(tmp); + if (EG(exception)) { _php_pgsql_free_params(params, num_params); - RETURN_FALSE; + return; } - params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val)); - zval_ptr_dtor(&tmp_val); + params[i] = estrndup(ZSTR_VAL(tmp_str), ZSTR_LEN(tmp_str)); + zend_string_release(tmp_str); } i++; @@ -6103,8 +6105,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con break; case IS_LONG: - ZVAL_LONG(&new_val, Z_LVAL_P(val)); - convert_to_string_ex(&new_val); + ZVAL_STR(&new_val, zend_long_to_str(Z_LVAL_P(val))); break; case IS_DOUBLE: @@ -6412,8 +6413,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con break; case IS_LONG: - ZVAL_LONG(&new_val, Z_LVAL_P(val)); - convert_to_string_ex(&new_val); + ZVAL_STR(&new_val, zend_long_to_str(Z_LVAL_P(val))); break; case IS_DOUBLE: diff --git a/ext/readline/readline.c b/ext/readline/readline.c index b66928ebd6..9c018bf9c8 100644 --- a/ext/readline/readline.c +++ b/ext/readline/readline.c @@ -279,7 +279,9 @@ PHP_FUNCTION(readline_info) oldstr = rl_line_buffer; if (value) { /* XXX if (rl_line_buffer) free(rl_line_buffer); */ - convert_to_string_ex(value); + if (!try_convert_to_string(value)) { + return; + } rl_line_buffer = strdup(Z_STRVAL_P(value)); } RETVAL_STRING(SAFE_STRING(oldstr)); @@ -302,7 +304,9 @@ PHP_FUNCTION(readline_info) } else if (!strcasecmp(what, "pending_input")) { oldval = rl_pending_input; if (value) { - convert_to_string_ex(value); + if (!try_convert_to_string(value)) { + return; + } rl_pending_input = Z_STRVAL_P(value)[0]; } RETVAL_LONG(oldval); @@ -319,7 +323,9 @@ PHP_FUNCTION(readline_info) } else if (!strcasecmp(what, "completion_append_character")) { oldval = rl_completion_append_character; if (value) { - convert_to_string_ex(value) + if (!try_convert_to_string(value)) { + return; + } rl_completion_append_character = (int)Z_STRVAL_P(value)[0]; } RETVAL_INTERNED_STR( @@ -342,7 +348,9 @@ PHP_FUNCTION(readline_info) oldstr = (char*)rl_readline_name; if (value) { /* XXX if (rl_readline_name) free(rl_readline_name); */ - convert_to_string_ex(value); + if (!try_convert_to_string(value)) { + return; + } rl_readline_name = strdup(Z_STRVAL_P(value)); } RETVAL_STRING(SAFE_STRING(oldstr)); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index e6ca3322cb..4623efb3cf 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2263,7 +2263,7 @@ ZEND_METHOD(reflection_parameter, __construct) case IS_ARRAY: { zval *classref; zval *method; - zend_string *lcname; + zend_string *name, *lcname; if (((classref = zend_hash_index_find(Z_ARRVAL_P(reference), 0)) == NULL) || ((method = zend_hash_index_find(Z_ARRVAL_P(reference), 1)) == NULL)) @@ -2275,27 +2275,38 @@ ZEND_METHOD(reflection_parameter, __construct) if (Z_TYPE_P(classref) == IS_OBJECT) { ce = Z_OBJCE_P(classref); } else { - convert_to_string_ex(classref); - if ((ce = zend_lookup_class(Z_STR_P(classref))) == NULL) { + name = zval_get_string(classref); + if (EG(exception)) { + return; + } + if ((ce = zend_lookup_class(name)) == NULL) { zend_throw_exception_ex(reflection_exception_ptr, 0, - "Class %s does not exist", Z_STRVAL_P(classref)); + "Class %s does not exist", ZSTR_VAL(name)); + zend_string_release(name); return; } + zend_string_release(name); + } + + name = zval_get_string(method); + if (EG(exception)) { + return; } - convert_to_string_ex(method); - lcname = zend_string_tolower(Z_STR_P(method)); + lcname = zend_string_tolower(name); if (Z_TYPE_P(classref) == IS_OBJECT && is_closure_invoke(ce, lcname) && (fptr = zend_get_closure_invoke_method(Z_OBJ_P(classref))) != NULL) { /* nothing to do. don't set is_closure since is the invoke handler, not the closure itself */ } else if ((fptr = zend_hash_find_ptr(&ce->function_table, lcname)) == NULL) { + zend_string_release(name); zend_string_release(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0, "Method %s::%s() does not exist", ZSTR_VAL(ce->name), Z_STRVAL_P(method)); return; } + zend_string_release(name); zend_string_release(lcname); } break; @@ -2329,29 +2340,23 @@ ZEND_METHOD(reflection_parameter, __construct) if (Z_TYPE_P(parameter) == IS_LONG) { position= (int)Z_LVAL_P(parameter); if (position < 0 || (uint32_t)position >= num_args) { - if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { - if (fptr->type != ZEND_OVERLOADED_FUNCTION) { - zend_string_release_ex(fptr->common.function_name, 0); - } - zend_free_trampoline(fptr); - } - if (is_closure) { - zval_ptr_dtor(reference); - } _DO_THROW("The parameter specified by its offset could not be found"); - return; + goto failure; } } else { uint32_t i; - position= -1; - convert_to_string_ex(parameter); + position = -1; + if (!try_convert_to_string(parameter)) { + goto failure; + } + if (fptr->type == ZEND_INTERNAL_FUNCTION && !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { for (i = 0; i < num_args; i++) { if (arg_info[i].name) { if (strcmp(((zend_internal_arg_info*)arg_info)[i].name, Z_STRVAL_P(parameter)) == 0) { - position= i; + position = i; break; } @@ -2361,24 +2366,15 @@ ZEND_METHOD(reflection_parameter, __construct) for (i = 0; i < num_args; i++) { if (arg_info[i].name) { if (strcmp(ZSTR_VAL(arg_info[i].name), Z_STRVAL_P(parameter)) == 0) { - position= i; + position = i; break; } } } } if (position == -1) { - if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { - if (fptr->type != ZEND_OVERLOADED_FUNCTION) { - zend_string_release_ex(fptr->common.function_name, 0); - } - zend_free_trampoline(fptr); - } - if (is_closure) { - zval_ptr_dtor(reference); - } _DO_THROW("The parameter specified by its name could not be found"); - return; + goto failure; } } @@ -2406,6 +2402,18 @@ ZEND_METHOD(reflection_parameter, __construct) } else { ZVAL_NULL(prop_name); } + return; + +failure: + if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { + if (fptr->type != ZEND_OVERLOADED_FUNCTION) { + zend_string_release_ex(fptr->common.function_name, 0); + } + zend_free_trampoline(fptr); + } + if (is_closure) { + zval_ptr_dtor(reference); + } } /* }}} */ @@ -3692,7 +3700,10 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob ZVAL_COPY(&intern->obj, argument); } } else { - convert_to_string_ex(argument); + if (!try_convert_to_string(argument)) { + return; + } + if ((ce = zend_lookup_class(Z_STR_P(argument))) == NULL) { if (!EG(exception)) { zend_throw_exception_ex(reflection_exception_ptr, -1, "Class %s does not exist", Z_STRVAL_P(argument)); diff --git a/ext/reflection/tests/bug74673.phpt b/ext/reflection/tests/bug74673.phpt index 8e4e8e3a18..47f7604e8b 100644 --- a/ext/reflection/tests/bug74673.phpt +++ b/ext/reflection/tests/bug74673.phpt @@ -19,4 +19,9 @@ $class = new ReflectionClass('A'); echo $class; ?> --EXPECTF-- -Fatal error: Method ReflectionClass::__toString() must not throw an exception, caught Exception: in %sbug74673.php on line %d +Fatal error: Uncaught Exception in %s:%d +Stack trace: +#0 [internal function]: {closure}(2, 'Use of undefine...', %s, %d, Array) +#1 %s(%d): ReflectionClass->__toString() +#2 {main} + thrown in %s on line %d diff --git a/ext/session/session.c b/ext/session/session.c index bf3ddee0d5..671968e8da 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -1752,35 +1752,36 @@ static PHP_FUNCTION(session_set_cookie_params) lifetime = zval_get_string(lifetime_or_options); } + /* Exception during string conversion */ + if (EG(exception)) { + goto cleanup; + } + if (lifetime) { ini_name = zend_string_init("session.cookie_lifetime", sizeof("session.cookie_lifetime") - 1, 0); result = zend_alter_ini_entry(ini_name, lifetime, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); - zend_string_release(lifetime); zend_string_release_ex(ini_name, 0); if (result == FAILURE) { - RETURN_FALSE; + RETVAL_FALSE; + goto cleanup; } } if (path) { ini_name = zend_string_init("session.cookie_path", sizeof("session.cookie_path") - 1, 0); result = zend_alter_ini_entry(ini_name, path, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); - if (found > 0) { - zend_string_release(path); - } zend_string_release_ex(ini_name, 0); if (result == FAILURE) { - RETURN_FALSE; + RETVAL_FALSE; + goto cleanup; } } if (domain) { ini_name = zend_string_init("session.cookie_domain", sizeof("session.cookie_domain") - 1, 0); result = zend_alter_ini_entry(ini_name, domain, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); - if (found > 0) { - zend_string_release(domain); - } zend_string_release_ex(ini_name, 0); if (result == FAILURE) { - RETURN_FALSE; + RETVAL_FALSE; + goto cleanup; } } if (!secure_null) { @@ -1788,7 +1789,8 @@ static PHP_FUNCTION(session_set_cookie_params) result = zend_alter_ini_entry_chars(ini_name, secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); if (result == FAILURE) { - RETURN_FALSE; + RETVAL_FALSE; + goto cleanup; } } if (!httponly_null) { @@ -1796,22 +1798,29 @@ static PHP_FUNCTION(session_set_cookie_params) result = zend_alter_ini_entry_chars(ini_name, httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); if (result == FAILURE) { - RETURN_FALSE; + RETVAL_FALSE; + goto cleanup; } } if (samesite) { ini_name = zend_string_init("session.cookie_samesite", sizeof("session.cookie_samesite") - 1, 0); result = zend_alter_ini_entry(ini_name, samesite, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); - if (found > 0) { - zend_string_release(samesite); - } zend_string_release_ex(ini_name, 0); if (result == FAILURE) { - RETURN_FALSE; + RETVAL_FALSE; + goto cleanup; } } - RETURN_TRUE; + RETVAL_TRUE; + +cleanup: + if (lifetime) zend_string_release(lifetime); + if (found > 0) { + if (path) zend_string_release(path); + if (domain) zend_string_release(domain); + if (samesite) zend_string_release(samesite); + } } /* }}} */ @@ -2364,7 +2373,10 @@ static PHP_FUNCTION(session_cache_expire) RETVAL_LONG(PS(cache_expire)); if (expires) { - convert_to_string_ex(expires); + if (!try_convert_to_string(expires)) { + return; + } + ini_name = zend_string_init("session.cache_expire", sizeof("session.cache_expire") - 1, 0); zend_alter_ini_entry(ini_name, Z_STR_P(expires), ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index fb55b6b195..01c119888e 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -260,6 +260,9 @@ long_dim: if (Z_TYPE_P(member) != IS_STRING) { ZVAL_STR(&tmp_zv, zval_get_string_func(member)); member = &tmp_zv; + if (EG(exception)) { + return &EG(uninitialized_zval); + } } name = Z_STRVAL_P(member); } @@ -455,6 +458,10 @@ long_dim: } else { if (Z_TYPE_P(member) != IS_STRING) { trim_str = zval_get_string_func(member); + if (EG(exception)) { + return &EG(error_zval); + } + ZVAL_STR(&tmp_zv, php_trim(trim_str, NULL, 0, 3)); zend_string_release_ex(trim_str, 0); member = &tmp_zv; @@ -672,10 +679,12 @@ static zval *sxe_property_get_adr(zval *object, zval *member, int fetch_type, vo char *name; SXE_ITER type; - sxe = Z_SXEOBJ_P(object); + if (!try_convert_to_string(member)) { + return NULL; + } + sxe = Z_SXEOBJ_P(object); GET_NODE(sxe, node); - convert_to_string(member); name = Z_STRVAL_P(member); node = sxe_get_element_by_name(sxe, node, &name, &type); if (node) { @@ -713,6 +722,9 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) { ZVAL_STR(&tmp_zv, zval_get_string_func(member)); member = &tmp_zv; + if (EG(exception)) { + return 0; + } } sxe = Z_SXEOBJ_P(object); @@ -832,6 +844,9 @@ static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements, if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) { ZVAL_STR(&tmp_zv, zval_get_string_func(member)); member = &tmp_zv; + if (EG(exception)) { + return; + } } sxe = Z_SXEOBJ_P(object); diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c index 34e951b6ec..69ff9b00f4 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -1920,6 +1920,9 @@ zval *php_snmp_read_property(zval *object, zval *member, int type, void **cache_ if (Z_TYPE_P(member) != IS_STRING) { ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; + if (EG(exception)) { + return &EG(uninitialized_zval); + } } hnd = zend_hash_find_ptr(&php_snmp_properties, Z_STR_P(member)); @@ -1954,6 +1957,9 @@ zval *php_snmp_write_property(zval *object, zval *member, zval *value, void **ca if (Z_TYPE_P(member) != IS_STRING) { ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; + if (EG(exception)) { + return value; + } } obj = Z_SNMP_P(object); diff --git a/ext/sockets/conversions.c b/ext/sockets/conversions.c index a9f287a8ea..f24e0926ce 100644 --- a/ext/sockets/conversions.c +++ b/ext/sockets/conversions.c @@ -332,7 +332,10 @@ double_case: zend_long lval; double dval; - convert_to_string(&lzval); + if (!try_convert_to_string(&lzval)) { + ctx->err.has_error = 1; + break; + } switch (is_numeric_string(Z_STRVAL(lzval), Z_STRLEN(lzval), &lval, &dval, 0)) { case IS_DOUBLE: diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 697d5f1d91..defb9fdb88 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -1066,23 +1066,18 @@ static void spl_recursive_tree_iterator_get_entry(spl_recursive_it_object *objec { zend_object_iterator *iterator = object->iterators[object->level].iterator; zval *data; - zend_error_handling error_handling; data = iterator->funcs->get_current_data(iterator); - - /* Replace exception handling so the catchable fatal error that is thrown when a class - * without __toString is converted to string is converted into an exception. */ - zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling); if (data) { ZVAL_DEREF(data); + /* TODO: Remove this special case? */ if (Z_TYPE_P(data) == IS_ARRAY) { - ZVAL_STRINGL(return_value, "Array", sizeof("Array")-1); + RETVAL_INTERNED_STR(ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED)); } else { ZVAL_COPY(return_value, data); convert_to_string(return_value); } } - zend_restore_error_handling(&error_handling); } static void spl_recursive_tree_iterator_get_postfix(spl_recursive_it_object *object, zval *return_value) @@ -2006,7 +2001,7 @@ SPL_METHOD(RegexIterator, accept) spl_dual_it_object *intern; zend_string *result, *subject; size_t count = 0; - zval zcount, *replacement, tmp_replacement, rv; + zval zcount, rv; pcre2_match_data *match_data; pcre2_code *re; int rc; @@ -2030,6 +2025,11 @@ SPL_METHOD(RegexIterator, accept) subject = zval_get_string(&intern->current.data); } + /* Exception during string conversion. */ + if (EG(exception)) { + return; + } + switch (intern->u.regex.mode) { case REGIT_MODE_MAX: /* won't happen but makes compiler happy */ @@ -2061,14 +2061,14 @@ SPL_METHOD(RegexIterator, accept) RETVAL_BOOL(count > 1); break; - case REGIT_MODE_REPLACE: - replacement = zend_read_property(intern->std.ce, ZEND_THIS, "replacement", sizeof("replacement")-1, 1, &rv); - if (Z_TYPE_P(replacement) != IS_STRING) { - ZVAL_COPY(&tmp_replacement, replacement); - convert_to_string(&tmp_replacement); - replacement = &tmp_replacement; + case REGIT_MODE_REPLACE: { + zval *replacement = zend_read_property(intern->std.ce, ZEND_THIS, "replacement", sizeof("replacement")-1, 1, &rv); + zend_string *replacement_str = zval_get_string(replacement); + if (EG(exception)) { + return; } - result = php_pcre_replace_impl(intern->u.regex.pce, subject, ZSTR_VAL(subject), ZSTR_LEN(subject), Z_STR_P(replacement), -1, &count); + + result = php_pcre_replace_impl(intern->u.regex.pce, subject, ZSTR_VAL(subject), ZSTR_LEN(subject), replacement_str, -1, &count); if (intern->u.regex.flags & REGIT_USE_KEY) { zval_ptr_dtor(&intern->current.key); @@ -2078,10 +2078,9 @@ SPL_METHOD(RegexIterator, accept) ZVAL_STR(&intern->current.data, result); } - if (replacement == &tmp_replacement) { - zval_ptr_dtor(replacement); - } + zend_string_release(replacement_str); RETVAL_BOOL(count > 0); + } } if (intern->u.regex.flags & REGIT_INVERTED) { diff --git a/ext/spl/tests/iterator_036.phpt b/ext/spl/tests/iterator_036.phpt index 74d393b677..07a1f79134 100644 --- a/ext/spl/tests/iterator_036.phpt +++ b/ext/spl/tests/iterator_036.phpt @@ -18,4 +18,9 @@ test(new CachingIterator($ar, 0)); ?> ===DONE=== --EXPECTF-- -Fatal error: Method CachingIterator::__toString() must not throw an exception, caught BadMethodCallException: CachingIterator does not fetch string value (see CachingIterator::__construct) in %siterator_036.php on line %d +Fatal error: Uncaught BadMethodCallException: CachingIterator does not fetch string value (see CachingIterator::__construct) in %s:%d +Stack trace: +#0 %s(%d): CachingIterator->__toString() +#1 %s(%d): test(Object(CachingIterator)) +#2 {main} + thrown in %s on line %d diff --git a/ext/spl/tests/recursive_tree_iterator_007.phpt b/ext/spl/tests/recursive_tree_iterator_007.phpt index 7374a066fa..a017254df0 100644 --- a/ext/spl/tests/recursive_tree_iterator_007.phpt +++ b/ext/spl/tests/recursive_tree_iterator_007.phpt @@ -22,12 +22,12 @@ try { foreach(new RecursiveTreeIterator($it) as $k => $v) { echo "[$k] => $v\n"; } -} catch (UnexpectedValueException $e) { - echo "UnexpectedValueException thrown\n"; +} catch (Error $e) { + echo $e->getMessage(), "\n"; } ?> ===DONE=== --EXPECT-- -UnexpectedValueException thrown +Object of class stdClass could not be converted to string ===DONE=== diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index b993d622ff..c3ffeabc00 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -801,10 +801,16 @@ static int sqlite3_do_callback(struct php_sqlite3_fci *fc, zval *cb, int argc, s sqlite3_result_double(context, Z_DVAL(retval)); break; - default: - convert_to_string_ex(&retval); - sqlite3_result_text(context, Z_STRVAL(retval), Z_STRLEN(retval), SQLITE_TRANSIENT); + default: { + zend_string *str = zval_get_string(&retval); + if (EG(exception)) { + ret = FAILURE; + break; + } + sqlite3_result_text(context, ZSTR_VAL(str), ZSTR_LEN(str), SQLITE_TRANSIENT); + zend_string_release(str); break; + } } } else { sqlite3_result_error(context, "failed to invoke callback", 0); @@ -1480,13 +1486,18 @@ static int php_sqlite3_bind_params(php_sqlite3_stmt *stmt_obj) /* {{{ */ break; } - case SQLITE3_TEXT: - convert_to_string(parameter); - return_code = sqlite3_bind_text(stmt_obj->stmt, param->param_number, Z_STRVAL_P(parameter), Z_STRLEN_P(parameter), SQLITE_STATIC); + case SQLITE3_TEXT: { + zend_string *str = zval_get_string(parameter); + if (EG(exception)) { + return FAILURE; + } + return_code = sqlite3_bind_text(stmt_obj->stmt, param->param_number, ZSTR_VAL(str), ZSTR_LEN(str), SQLITE_TRANSIENT); if (return_code != SQLITE_OK) { php_sqlite3_error(stmt_obj->db_obj, "Unable to bind parameter number " ZEND_LONG_FMT " (%d)", param->param_number, return_code); } + zend_string_release(str); break; + } case SQLITE_NULL: return_code = sqlite3_bind_null(stmt_obj->stmt, param->param_number); @@ -1526,7 +1537,7 @@ PHP_METHOD(sqlite3stmt, getSQL) bind_rc = php_sqlite3_bind_params(stmt_obj); - if (bind_rc == FAILURE) { + if (bind_rc == FAILURE || EG(exception)) { RETURN_FALSE; } @@ -1718,7 +1729,7 @@ PHP_METHOD(sqlite3stmt, execute) /* Bind parameters to the statement */ bind_rc = php_sqlite3_bind_params(stmt_obj); - if (bind_rc == FAILURE) { + if (bind_rc == FAILURE || EG(exception)) { RETURN_FALSE; } diff --git a/ext/sqlite3/tests/exception_from_toString.phpt b/ext/sqlite3/tests/exception_from_toString.phpt new file mode 100644 index 0000000000..1d6ed39f2a --- /dev/null +++ b/ext/sqlite3/tests/exception_from_toString.phpt @@ -0,0 +1,39 @@ +--TEST-- +Check that exceptions from __toString() are handled correctly +--FILE-- +<?php + +class throws { + function __toString() { + throw new Exception("Sorry"); + } +} + +$db = new sqlite3(':memory:'); +$db->exec('CREATE TABLE t(id int, v varchar(255))'); + +$stmt = $db->prepare('INSERT INTO t VALUES(:i, :v)'); +$stmt->bindValue('i', 1234); +$stmt->bindValue('v', new throws); + +try { + $stmt->execute(); +} catch (Exception $e) { + echo "Exception thrown ...\n"; +} + +try { + $stmt->execute(); +} catch (Exception $e) { + echo "Exception thrown ...\n"; +} + +$query = $db->query("SELECT * FROM t"); +while ($row = $query->fetchArray(SQLITE3_ASSOC)) { + print_r($row); +} + +?> +--EXPECT-- +Exception thrown ... +Exception thrown ... diff --git a/ext/standard/array.c b/ext/standard/array.c index 5448a1815d..71a7cf17e7 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2458,7 +2458,10 @@ PHP_FUNCTION(extract) } if (prefix) { - convert_to_string(prefix); + if (!try_convert_to_string(prefix)) { + return; + } + if (Z_STRLEN_P(prefix) && !php_valid_var_name(Z_STRVAL_P(prefix), Z_STRLEN_P(prefix))) { php_error_docref(NULL, E_WARNING, "prefix is not a valid identifier"); return; @@ -4134,7 +4137,9 @@ zend_bool array_column_param_helper(zval *param, return 1; case IS_OBJECT: - convert_to_string_ex(param); + if (!try_convert_to_string(param)) { + return 0; + } /* fallthrough */ case IS_STRING: return 1; diff --git a/ext/standard/assert.c b/ext/standard/assert.c index eb1b59db74..6e21af6dd5 100644 --- a/ext/standard/assert.c +++ b/ext/standard/assert.c @@ -300,6 +300,10 @@ PHP_FUNCTION(assert_options) oldint = ASSERTG(active); if (ac == 2) { zend_string *value_str = zval_get_string(value); + if (EG(exception)) { + return; + } + key = zend_string_init("assert.active", sizeof("assert.active")-1, 0); zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0); zend_string_release_ex(key, 0); @@ -312,6 +316,10 @@ PHP_FUNCTION(assert_options) oldint = ASSERTG(bail); if (ac == 2) { zend_string *value_str = zval_get_string(value); + if (EG(exception)) { + return; + } + key = zend_string_init("assert.bail", sizeof("assert.bail")-1, 0); zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0); zend_string_release_ex(key, 0); @@ -324,6 +332,10 @@ PHP_FUNCTION(assert_options) oldint = ASSERTG(quiet_eval); if (ac == 2) { zend_string *value_str = zval_get_string(value); + if (EG(exception)) { + return; + } + key = zend_string_init("assert.quiet_eval", sizeof("assert.quiet_eval")-1, 0); zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0); zend_string_release_ex(key, 0); @@ -336,6 +348,10 @@ PHP_FUNCTION(assert_options) oldint = ASSERTG(warning); if (ac == 2) { zend_string *value_str = zval_get_string(value); + if (EG(exception)) { + return; + } + key = zend_string_init("assert.warning", sizeof("assert.warning")-1, 0); zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0); zend_string_release_ex(key, 0); @@ -361,8 +377,12 @@ PHP_FUNCTION(assert_options) case ASSERT_EXCEPTION: oldint = ASSERTG(exception); if (ac == 2) { - zend_string *key = zend_string_init("assert.exception", sizeof("assert.exception")-1, 0); zend_string *val = zval_get_string(value); + if (EG(exception)) { + return; + } + + key = zend_string_init("assert.exception", sizeof("assert.exception")-1, 0); zend_alter_ini_entry_ex(key, val, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0); zend_string_release_ex(val, 0); zend_string_release_ex(key, 0); diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 920974fe48..8d4dec48c1 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -5357,7 +5357,10 @@ PHP_FUNCTION(highlight_string) Z_PARAM_OPTIONAL Z_PARAM_BOOL(i) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); - convert_to_string_ex(expr); + + if (!try_convert_to_string(expr)) { + return; + } if (i) { php_output_start_default(); diff --git a/ext/standard/filters.c b/ext/standard/filters.c index 9d90558f59..83fcf2dcbf 100644 --- a/ext/standard/filters.c +++ b/ext/standard/filters.c @@ -250,8 +250,6 @@ static php_stream_filter *strfilter_strip_tags_create(const char *filtername, zv php_error_docref(NULL, E_DEPRECATED, "The string.strip_tags filter is deprecated"); - inst = pemalloc(sizeof(php_strip_tags_filter), persistent); - if (filterparams != NULL) { if (Z_TYPE_P(filterparams) == IS_ARRAY) { smart_str tags_ss = {0}; @@ -268,8 +266,17 @@ static php_stream_filter *strfilter_strip_tags_create(const char *filtername, zv } else { allowed_tags = zval_get_string(filterparams); } + + /* Exception during string conversion. */ + if (EG(exception)) { + if (allowed_tags) { + zend_string_release(allowed_tags); + } + return NULL; + } } + inst = pemalloc(sizeof(php_strip_tags_filter), persistent); if (php_strip_tags_filter_ctor(inst, allowed_tags, persistent) == SUCCESS) { filter = php_stream_filter_alloc(&strfilter_strip_tags_ops, inst, persistent); } else { diff --git a/ext/standard/formatted_print.c b/ext/standard/formatted_print.c index b804cda500..4ee68adefa 100644 --- a/ext/standard/formatted_print.c +++ b/ext/standard/formatted_print.c @@ -400,7 +400,10 @@ php_formatted_print(zval *z_format, zval *args, int argc) int always_sign; size_t format_len; - convert_to_string_ex(z_format); + if (!try_convert_to_string(z_format)) { + return NULL; + } + format = Z_STRVAL_P(z_format); format_len = Z_STRLEN_P(z_format); result = zend_string_alloc(size, 0); diff --git a/ext/standard/head.c b/ext/standard/head.c index e8b5d5b171..f1b2fa4e8b 100644 --- a/ext/standard/head.c +++ b/ext/standard/head.c @@ -258,10 +258,12 @@ PHP_FUNCTION(setcookie) } } - if (php_setcookie(name, value, expires, path, domain, secure, httponly, samesite, 1) == SUCCESS) { - RETVAL_TRUE; - } else { - RETVAL_FALSE; + if (!EG(exception)) { + if (php_setcookie(name, value, expires, path, domain, secure, httponly, samesite, 1) == SUCCESS) { + RETVAL_TRUE; + } else { + RETVAL_FALSE; + } } if (expires_or_options && Z_TYPE_P(expires_or_options) == IS_ARRAY) { @@ -311,10 +313,12 @@ PHP_FUNCTION(setrawcookie) } } - if (php_setcookie(name, value, expires, path, domain, secure, httponly, samesite, 0) == SUCCESS) { - RETVAL_TRUE; - } else { - RETVAL_FALSE; + if (!EG(exception)) { + if (php_setcookie(name, value, expires, path, domain, secure, httponly, samesite, 0) == SUCCESS) { + RETVAL_TRUE; + } else { + RETVAL_FALSE; + } } if (expires_or_options && Z_TYPE_P(expires_or_options) == IS_ARRAY) { diff --git a/ext/standard/math.c b/ext/standard/math.c index cefcd38769..840df9103e 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -1090,7 +1090,10 @@ PHP_FUNCTION(base_convert) Z_PARAM_LONG(frombase) Z_PARAM_LONG(tobase) ZEND_PARSE_PARAMETERS_END(); - convert_to_string_ex(number); + + if (!try_convert_to_string(number)) { + return; + } if (frombase < 2 || frombase > 36) { php_error_docref(NULL, E_WARNING, "Invalid `from base' (" ZEND_LONG_FMT ")", frombase); diff --git a/ext/standard/pack.c b/ext/standard/pack.c index 5f375585d4..3c0dc009f1 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -297,7 +297,12 @@ PHP_FUNCTION(pack) } if (arg < 0) { - convert_to_string(&argv[currentarg]); + if (!try_convert_to_string(&argv[currentarg])) { + efree(formatcodes); + efree(formatargs); + return; + } + arg = Z_STRLEN(argv[currentarg]); if (code == 'Z') { /* add one because Z is always NUL-terminated: diff --git a/ext/standard/password.c b/ext/standard/password.c index 3f1ff6dd55..52ff1518e6 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -140,6 +140,9 @@ static zend_string* php_password_get_salt(zval *unused_, size_t required_salt_le case IS_DOUBLE: case IS_OBJECT: buffer = zval_get_string(option_buffer); + if (EG(exception)) { + return NULL; + } break; case IS_FALSE: case IS_TRUE: diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 326cfc1431..d76e1595f3 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -552,7 +552,9 @@ PHP_FUNCTION(proc_open) } else { if ((ztype = zend_hash_index_find(Z_ARRVAL_P(descitem), 0)) != NULL) { - convert_to_string_ex(ztype); + if (!try_convert_to_string(ztype)) { + goto exit_fail; + } } else { php_error_docref(NULL, E_WARNING, "Missing handle qualifier in array"); goto exit_fail; @@ -563,7 +565,9 @@ PHP_FUNCTION(proc_open) zval *zmode; if ((zmode = zend_hash_index_find(Z_ARRVAL_P(descitem), 1)) != NULL) { - convert_to_string_ex(zmode); + if (!try_convert_to_string(zmode)) { + goto exit_fail; + } } else { php_error_docref(NULL, E_WARNING, "Missing mode parameter for 'pipe'"); goto exit_fail; @@ -602,14 +606,18 @@ PHP_FUNCTION(proc_open) descriptors[ndesc].mode = DESC_FILE; if ((zfile = zend_hash_index_find(Z_ARRVAL_P(descitem), 1)) != NULL) { - convert_to_string_ex(zfile); + if (!try_convert_to_string(zfile)) { + goto exit_fail; + } } else { php_error_docref(NULL, E_WARNING, "Missing file name parameter for 'file'"); goto exit_fail; } if ((zmode = zend_hash_index_find(Z_ARRVAL_P(descitem), 2)) != NULL) { - convert_to_string_ex(zmode); + if (!try_convert_to_string(zmode)) { + goto exit_fail; + } } else { php_error_docref(NULL, E_WARNING, "Missing mode parameter for 'file'"); goto exit_fail; diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 4fa705bed9..24d8357d7f 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -1576,7 +1576,9 @@ PHP_FUNCTION(stream_is_local) } wrapper = stream->wrapper; } else { - convert_to_string_ex(zstream); + if (!try_convert_to_string(zstream)) { + return; + } wrapper = php_stream_locate_url_wrapper(Z_STRVAL_P(zstream), NULL, 0); } diff --git a/ext/standard/string.c b/ext/standard/string.c index e0141ffaea..a7aa02fcbd 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -2494,6 +2494,10 @@ PHP_FUNCTION(substr_replace) convert_to_long_ex(from); } + if (EG(exception)) { + return; + } + if (argc > 3) { if (Z_TYPE_P(len) != IS_ARRAY) { convert_to_long_ex(len); @@ -3518,7 +3522,9 @@ PHP_FUNCTION(strtr) php_strtr_array(return_value, str, pats); } } else { - convert_to_string_ex(from); + if (!try_convert_to_string(from)) { + return; + } RETURN_STR(php_strtr_ex(str, Z_STRVAL_P(from), @@ -4438,6 +4444,10 @@ static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensit convert_to_string_ex(replace); } + if (EG(exception)) { + return; + } + /* if subject is an array */ if (Z_TYPE_P(subject) == IS_ARRAY) { array_init(return_value); @@ -4840,6 +4850,9 @@ PHP_FUNCTION(setlocale) } loc = zval_get_string(plocale); + if (EG(exception)) { + return; + } if (!strcmp("0", ZSTR_VAL(loc))) { zend_string_release_ex(loc, 0); diff --git a/ext/standard/tests/array/array_multisort_variation8.phpt b/ext/standard/tests/array/array_multisort_variation8.phpt index 6d89dd0c6c..00b0ccb012 100644 --- a/ext/standard/tests/array/array_multisort_variation8.phpt +++ b/ext/standard/tests/array/array_multisort_variation8.phpt @@ -34,7 +34,6 @@ $inputs = array( 'empty string DQ' => "", 'string DQ' => "string", 'instance of classWithToString' => new classWithToString(), - 'instance of classWithoutToString' => new classWithoutToString(), 'undefined var' => @$undefined_var, ); @@ -46,14 +45,11 @@ var_dump($inputs); --EXPECT-- *** Testing array_multisort() : usage variation - test sort order of all types*** bool(true) -array(10) { +array(9) { ["uppercase NULL"]=> NULL ["empty string DQ"]=> string(0) "" - ["instance of classWithoutToString"]=> - object(classWithoutToString)#2 (0) { - } ["undefined var"]=> NULL ["float -10.5"]=> diff --git a/ext/standard/tests/class_object/get_class_methods_variation_001.phpt b/ext/standard/tests/class_object/get_class_methods_variation_001.phpt index 16a728e088..dd852ef61f 100644 --- a/ext/standard/tests/class_object/get_class_methods_variation_001.phpt +++ b/ext/standard/tests/class_object/get_class_methods_variation_001.phpt @@ -76,10 +76,9 @@ $values = array( // loop through each element of the array for class foreach($values as $value) { - echo "\nArg value $value \n"; + echo "\nArg value " . (is_object($value) ? get_class($value) : $value) . " \n"; var_dump( get_class_methods($value) ); }; - echo "Done"; ?> --EXPECTF-- @@ -163,9 +162,8 @@ NULL Arg value string NULL -Error: 4096 - Object of class stdClass could not be converted to string, %s(76) -Arg value +Arg value stdClass array(0) { } diff --git a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt index 8dde525ae8..0ad5756837 100644 --- a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt +++ b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt @@ -77,7 +77,7 @@ $values = array( // loop through each element of the array for object foreach($values as $value) { - echo "\nArg value $value \n"; + echo "\nArg value " . (is_object($value) ? get_class($value) : $value) . " \n"; var_dump( get_parent_class($value) ); }; @@ -166,9 +166,8 @@ bool(false) Arg value String In autoload(String) bool(false) -Error: 4096 - Object of class stdClass could not be converted to string, %s(77) -Arg value +Arg value stdClass bool(false) Arg value diff --git a/ext/standard/tests/general_functions/type.phpt b/ext/standard/tests/general_functions/type.phpt index 90bfb45f28..0b460b08d1 100644 --- a/ext/standard/tests/general_functions/type.phpt +++ b/ext/standard/tests/general_functions/type.phpt @@ -47,7 +47,11 @@ foreach ($array as $var) { foreach ($types as $type) { foreach ($array as $var) { - var_dump(settype($var, $type)); + try { + var_dump(settype($var, $type)); + } catch (Error $e) { + echo "Error: ", $e->getMessage(), "\n"; + } var_dump($var); } } @@ -344,7 +348,6 @@ bool(true) string(14) "Resource id #%d" bool(true) string(14) "Resource id #%d" -string(57) "Object of class stdClass could not be converted to string" -bool(true) -string(6) "Object" +Error: Object of class stdClass could not be converted to string +string(0) "" Done diff --git a/ext/standard/tests/math/base_convert_error.phpt b/ext/standard/tests/math/base_convert_error.phpt index f27d0a66cf..96e774b51f 100644 --- a/ext/standard/tests/math/base_convert_error.phpt +++ b/ext/standard/tests/math/base_convert_error.phpt @@ -22,7 +22,11 @@ base_convert(1234, 1, 10); base_convert(1234, 10, 37); echo "Incorrect input\n"; -base_convert(new classA(), 8, 10); +try { + base_convert(new classA(), 8, 10); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} ?> --EXPECTF-- @@ -39,5 +43,4 @@ Warning: base_convert(): Invalid `from base' (1) in %s on line %d Warning: base_convert(): Invalid `to base' (37) in %s on line %d Incorrect input - -Recoverable fatal error: Object of class classA could not be converted to string in %s on line %d +Object of class classA could not be converted to string diff --git a/ext/standard/tests/streams/bug61115.phpt b/ext/standard/tests/streams/bug61115.phpt index 5cfc9c2ac3..3caffde232 100644 --- a/ext/standard/tests/streams/bug61115.phpt +++ b/ext/standard/tests/streams/bug61115.phpt @@ -7,7 +7,11 @@ $arrayLarge = array_fill(0, 113663, '*'); $resourceFileTemp = fopen('php://temp', 'r+'); stream_context_set_params($resourceFileTemp, array()); -preg_replace('', function() {}, $resourceFileTemp); +try { + preg_replace('', function() {}, $resourceFileTemp); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} ?> --EXPECTF-- -Recoverable fatal error: Object of class Closure could not be converted to string in %s on line %d +Object of class Closure could not be converted to string diff --git a/ext/standard/tests/strings/strval_error.phpt b/ext/standard/tests/strings/strval_error.phpt index 37ecfd14d5..4e1ece6016 100644 --- a/ext/standard/tests/strings/strval_error.phpt +++ b/ext/standard/tests/strings/strval_error.phpt @@ -29,7 +29,11 @@ var_dump( strval() ); // Testing strval with a object which has no toString() method echo "\n-- Testing strval() function with object which has not toString() method --\n"; -var_dump( strval(new MyClass()) ); +try { + var_dump( strval(new MyClass()) ); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} ?> ===DONE=== @@ -47,5 +51,5 @@ Warning: strval() expects exactly 1 parameter, 0 given in %s on line %d NULL -- Testing strval() function with object which has not toString() method -- - -Recoverable fatal error: Object of class MyClass could not be converted to string in %s on line %d +Object of class MyClass could not be converted to string +===DONE=== diff --git a/ext/standard/var.c b/ext/standard/var.c index ca0273c213..410c0fdeb9 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -1222,6 +1222,13 @@ PHP_FUNCTION(unserialize) zend_hash_add_empty_element(class_hash, lcname); zend_string_release_ex(lcname, 0); } ZEND_HASH_FOREACH_END(); + + /* Exception during string conversion. */ + if (EG(exception)) { + zend_hash_destroy(class_hash); + FREE_HASHTABLE(class_hash); + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + } } php_var_unserialize_set_allowed_classes(var_hash, class_hash); } diff --git a/ext/xml/xml.c b/ext/xml/xml.c index f60f08bd57..fb60883226 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -1629,7 +1629,10 @@ PHP_FUNCTION(xml_parser_set_option) break; case PHP_XML_OPTION_TARGET_ENCODING: { const xml_encoding *enc; - convert_to_string_ex(val); + if (!try_convert_to_string(val)) { + return; + } + enc = xml_get_encoding((XML_Char*)Z_STRVAL_P(val)); if (enc == NULL) { php_error_docref(NULL, E_WARNING, "Unsupported target encoding \"%s\"", Z_STRVAL_P(val)); diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c index 3ce3fed0e1..b3b202af39 100644 --- a/ext/xmlreader/php_xmlreader.c +++ b/ext/xmlreader/php_xmlreader.c @@ -124,6 +124,9 @@ zval *xmlreader_get_property_ptr_ptr(zval *object, zval *member, int type, void if (Z_TYPE_P(member) != IS_STRING) { ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; + if (EG(exception)) { + return NULL; + } } obj = Z_XMLREADER_P(object); @@ -155,6 +158,9 @@ zval *xmlreader_read_property(zval *object, zval *member, int type, void **cache if (Z_TYPE_P(member) != IS_STRING) { ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; + if (EG(exception)) { + return &EG(uninitialized_zval); + } } obj = Z_XMLREADER_P(object); @@ -190,6 +196,9 @@ zval *xmlreader_write_property(zval *object, zval *member, zval *value, void **c if (Z_TYPE_P(member) != IS_STRING) { ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; + if (EG(exception)) { + return value; + } } obj = Z_XMLREADER_P(object); diff --git a/ext/xmlrpc/xmlrpc-epi-php.c b/ext/xmlrpc/xmlrpc-epi-php.c index 8d9ff87611..51dc647b19 100644 --- a/ext/xmlrpc/xmlrpc-epi-php.c +++ b/ext/xmlrpc/xmlrpc-epi-php.c @@ -522,7 +522,9 @@ static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int dep } break; case xmlrpc_datetime: - convert_to_string(&val); + if (!try_convert_to_string(&val)) { + return NULL; + } xReturn = XMLRPC_CreateValueDateTime_ISO8601(key, Z_STRVAL(val)); break; case xmlrpc_boolean: @@ -538,7 +540,9 @@ static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int dep xReturn = XMLRPC_CreateValueDouble(key, Z_DVAL(val)); break; case xmlrpc_string: - convert_to_string(&val); + if (!try_convert_to_string(&val)) { + return NULL; + } xReturn = XMLRPC_CreateValueString(key, Z_STRVAL(val), Z_STRLEN(val)); break; case xmlrpc_vector: @@ -925,7 +929,10 @@ static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data) STRUCT_XMLRPC_ERROR err = {0}; /* return value should be a string */ - convert_to_string(&retval); + if (!try_convert_to_string(&retval)) { + zend_string_release_ex(php_function_name, 0); + break; + } xData = XMLRPC_IntrospectionCreateDescription(Z_STRVAL(retval), &err); diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c index 18443f9efa..919006041a 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -150,7 +150,10 @@ static char **php_xsl_xslt_make_params(HashTable *parht, int xpath_params) return NULL; } else { if (Z_TYPE_P(value) != IS_STRING) { - convert_to_string(value); + if (!try_convert_to_string(value)) { + efree(params); + return NULL; + } } if (!xpath_params) { @@ -753,13 +756,16 @@ PHP_FUNCTION(xsl_xsltprocessor_set_parameter) if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "sa", &namespace, &namespace_len, &array_value) == SUCCESS) { intern = Z_XSL_P(id); ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(array_value), string_key, entry) { + zval tmp; if (string_key == NULL) { php_error_docref(NULL, E_WARNING, "Invalid parameter array"); RETURN_FALSE; } - convert_to_string_ex(entry); - Z_TRY_ADDREF_P(entry); - zend_hash_update(intern->parameter, string_key, entry); + ZVAL_STR(&tmp, zval_get_string(entry)); + if (EG(exception)) { + return; + } + zend_hash_update(intern->parameter, string_key, &tmp); } ZEND_HASH_FOREACH_END(); RETURN_TRUE; } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "sSS", &namespace, &namespace_len, &name, &value) == SUCCESS) { @@ -841,9 +847,13 @@ PHP_FUNCTION(xsl_xsltprocessor_register_php_functions) intern = Z_XSL_P(id); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array_value), entry) { - convert_to_string_ex(entry); - ZVAL_LONG(&new_string ,1); - zend_hash_update(intern->registered_phpfunctions, Z_STR_P(entry), &new_string); + zend_string *str = zval_get_string(entry); + if (EG(exception)) { + return; + } + ZVAL_LONG(&new_string, 1); + zend_hash_update(intern->registered_phpfunctions, str, &new_string); + zend_string_release(str); } ZEND_HASH_FOREACH_END(); intern->registerPhpFunctions = 2; diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index df3eade995..c2b41309c0 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -876,6 +876,9 @@ static zval *php_zip_get_property_ptr_ptr(zval *object, zval *member, int type, ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; cache_slot = NULL; + if (EG(exception)) { + return NULL; + } } obj = Z_ZIP_P(object); @@ -907,6 +910,9 @@ static zval *php_zip_read_property(zval *object, zval *member, int type, void ** ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; cache_slot = NULL; + if (EG(exception)) { + return &EG(uninitialized_zval); + } } obj = Z_ZIP_P(object); @@ -943,6 +949,9 @@ static int php_zip_has_property(zval *object, zval *member, int type, void **cac ZVAL_STR(&tmp_member, zval_get_string_func(member)); member = &tmp_member; cache_slot = NULL; + if (EG(exception)) { + return 0; + } } obj = Z_ZIP_P(object); diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index f3bda6398f..9060dcb2e2 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -777,7 +777,7 @@ static zend_bool zlib_create_dictionary_string(HashTable *options, char **dict, size_t i; *++ptr = zval_get_string(cur); - if (!*ptr || ZSTR_LEN(*ptr) == 0) { + if (!*ptr || ZSTR_LEN(*ptr) == 0 || EG(exception)) { if (*ptr) { efree(*ptr); } @@ -785,7 +785,9 @@ static zend_bool zlib_create_dictionary_string(HashTable *options, char **dict, efree(ptr); } efree(strings); - php_error_docref(NULL, E_WARNING, "dictionary entries must be non-empty strings"); + if (!EG(exception)) { + php_error_docref(NULL, E_WARNING, "dictionary entries must be non-empty strings"); + } return 0; } for (i = 0; i < ZSTR_LEN(*ptr); i++) { |