Skip to content
Merged
4 changes: 1 addition & 3 deletions Zend/Optimizer/sccp.c
Original file line number Diff line number Diff line change
Expand Up @@ -838,9 +838,7 @@ static inline zend_result ct_eval_func_call_ex(
zval_ptr_dtor(result);
zend_clear_exception();
retval = FAILURE;
}

if (EG(capture_warnings_during_sccp) > 1) {
} else if (EG(capture_warnings_during_sccp) > 1) {
zval_ptr_dtor(result);
retval = FAILURE;
}
Expand Down
27 changes: 27 additions & 0 deletions ext/opcache/tests/opt/gh19792.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
GH-19792 (SCCP causes UAF for return value if both warning and exception are triggered)
--EXTENSIONS--
opcache
zend_test
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.optimization_level=-1
--FILE--
<?php

function foo()
{
return \zend_test_gh19792();
}

try {
foo();
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECTF--
Warning: a warning in %s on line %d
an exception
31 changes: 31 additions & 0 deletions ext/standard/tests/serialize/gh19701.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
GH-19701 (Serialize/deserialize loses some data)
--CREDITS--
cuchac
DanielEScherzer
--FILE--
<?php

class Item {
public $children = [];
public $parent = null;

public function __sleep() {
return ["children", "parent"];
}
}

$baseProduct = new Item();

$child = new Item();
$child->parent = $baseProduct;
$baseProduct->children = [ $child ];

$data = [clone $baseProduct, $baseProduct];

echo serialize($data), "\n";

?>
--EXPECTF--
Deprecated: The __sleep() serialization magic method has been deprecated. Implement __serialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
a:2:{i:0;O:4:"Item":2:{s:8:"children";a:1:{i:0;O:4:"Item":2:{s:8:"children";a:0:{}s:6:"parent";O:4:"Item":2:{s:8:"children";a:1:{i:0;r:4;}s:6:"parent";N;}}}s:6:"parent";N;}i:1;r:6;}
9 changes: 1 addition & 8 deletions ext/standard/var.c
Original file line number Diff line number Diff line change
Expand Up @@ -1001,18 +1001,11 @@ static void php_var_serialize_nested_data(smart_str *buf, zval *struc, HashTable
/* we should still add element even if it's not OK,
* since we already wrote the length of the array before */
if (Z_TYPE_P(data) == IS_ARRAY) {
if (UNEXPECTED(Z_IS_RECURSIVE_P(data))
|| UNEXPECTED(Z_TYPE_P(struc) == IS_ARRAY && Z_ARR_P(data) == Z_ARR_P(struc))) {
if (UNEXPECTED(Z_TYPE_P(struc) == IS_ARRAY && Z_ARR_P(data) == Z_ARR_P(struc))) {
php_add_var_hash(var_hash, struc, in_rcn_array);
smart_str_appendl(buf, "N;", 2);
} else {
if (Z_REFCOUNTED_P(data)) {
Z_PROTECT_RECURSION_P(data);
}
php_var_serialize_intern(buf, data, var_hash, in_rcn_array, false);
if (Z_REFCOUNTED_P(data)) {
Z_UNPROTECT_RECURSION_P(data);
}
}
} else {
php_var_serialize_intern(buf, data, var_hash, in_rcn_array, false);
Expand Down
53 changes: 22 additions & 31 deletions ext/uri/php_uri.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,42 +58,43 @@ static HashTable *uri_get_debug_properties(zend_object *object)
HashTable *std_properties = zend_std_get_properties(object);
HashTable *result = zend_array_dup(std_properties);

if (UNEXPECTED(internal_uri->uri == NULL)) {
const php_uri_parser * const parser = internal_uri->parser;
void * const uri = internal_uri->uri;

if (UNEXPECTED(uri == NULL)) {
return result;
}

const php_uri_parser *parser = internal_uri->parser;

zval tmp;
if (parser->property_handler.scheme.read(internal_uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
if (parser->property_handler.scheme.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_SCHEME), &tmp);
}

if (parser->property_handler.username.read(internal_uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
if (parser->property_handler.username.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_USERNAME), &tmp);
}

if (parser->property_handler.password.read(internal_uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
if (parser->property_handler.password.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PASSWORD), &tmp);
}

if (parser->property_handler.host.read(internal_uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
if (parser->property_handler.host.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_HOST), &tmp);
}

if (parser->property_handler.port.read(internal_uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
if (parser->property_handler.port.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PORT), &tmp);
}

if (parser->property_handler.path.read(internal_uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
if (parser->property_handler.path.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PATH), &tmp);
}

if (parser->property_handler.query.read(internal_uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
if (parser->property_handler.query.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_QUERY), &tmp);
}

if (parser->property_handler.fragment.read(internal_uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
if (parser->property_handler.fragment.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_FRAGMENT), &tmp);
}

Expand Down Expand Up @@ -123,54 +124,44 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI uri_internal_t *php_uri_parse(const php_uri_parser
return internal_uri;
}

ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_get_property(const uri_internal_t *internal_uri, php_uri_property_name property_name, php_uri_component_read_mode read_mode, zval *zv)
{
const php_uri_property_handler *property_handler = uri_property_handler_from_internal_uri(internal_uri, property_name);
if (property_handler == NULL) {
return FAILURE;
}

return property_handler->read(internal_uri, read_mode, zv);
}

ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_scheme(const uri_internal_t *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, PHP_URI_PROPERTY_NAME_SCHEME, read_mode, zv);
return internal_uri->parser->property_handler.scheme.read(internal_uri->uri, read_mode, zv);
}

ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_username(const uri_internal_t *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, PHP_URI_PROPERTY_NAME_USERNAME, read_mode, zv);
return internal_uri->parser->property_handler.username.read(internal_uri->uri, read_mode, zv);
}

ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_password(const uri_internal_t *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, PHP_URI_PROPERTY_NAME_PASSWORD, read_mode, zv);
return internal_uri->parser->property_handler.password.read(internal_uri->uri, read_mode, zv);
}

ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_host(const uri_internal_t *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, PHP_URI_PROPERTY_NAME_HOST, read_mode, zv);
return internal_uri->parser->property_handler.host.read(internal_uri->uri, read_mode, zv);
}

ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_port(const uri_internal_t *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, PHP_URI_PROPERTY_NAME_PORT, read_mode, zv);
return internal_uri->parser->property_handler.port.read(internal_uri->uri, read_mode, zv);
}

ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_path(const uri_internal_t *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, PHP_URI_PROPERTY_NAME_PATH, read_mode, zv);
return internal_uri->parser->property_handler.path.read(internal_uri->uri, read_mode, zv);
}

ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_query(const uri_internal_t *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, PHP_URI_PROPERTY_NAME_QUERY, read_mode, zv);
return internal_uri->parser->property_handler.query.read(internal_uri->uri, read_mode, zv);
}

ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_fragment(const uri_internal_t *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, PHP_URI_PROPERTY_NAME_FRAGMENT, read_mode, zv);
return internal_uri->parser->property_handler.fragment.read(internal_uri->uri, read_mode, zv);
}

ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_free(uri_internal_t *internal_uri)
Expand Down Expand Up @@ -536,7 +527,7 @@ static void rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAMETERS, php_uri_componen
uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS);
URI_ASSERT_INITIALIZATION(internal_uri);

if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_read(internal_uri, read_mode, return_value) == FAILURE)) {
if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_read(internal_uri->uri, read_mode, return_value) == FAILURE)) {
zend_throw_error(NULL, "The userinfo component cannot be retrieved");
RETURN_THROWS();
}
Expand Down Expand Up @@ -583,7 +574,7 @@ PHP_METHOD(Uri_Rfc3986_Uri, withUserInfo)
uri_internal_t *new_internal_uri = uri_internal_from_obj(new_object);
URI_ASSERT_INITIALIZATION(new_internal_uri);

if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_write(new_internal_uri, &zv, NULL) == FAILURE)) {
if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_write(new_internal_uri->uri, &zv, NULL) == FAILURE)) {
RETURN_THROWS();
}
}
Expand Down
33 changes: 4 additions & 29 deletions ext/uri/php_uri_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,6 @@
#include "Zend/zend_exceptions.h"
#include "php_uri_common.h"

const php_uri_property_handler *uri_property_handler_from_internal_uri(const uri_internal_t *internal_uri, php_uri_property_name property_name)
{
switch (property_name) {
case PHP_URI_PROPERTY_NAME_SCHEME:
return &internal_uri->parser->property_handler.scheme;
case PHP_URI_PROPERTY_NAME_USERNAME:
return &internal_uri->parser->property_handler.username;
case PHP_URI_PROPERTY_NAME_PASSWORD:
return &internal_uri->parser->property_handler.password;
case PHP_URI_PROPERTY_NAME_HOST:
return &internal_uri->parser->property_handler.host;
case PHP_URI_PROPERTY_NAME_PORT:
return &internal_uri->parser->property_handler.port;
case PHP_URI_PROPERTY_NAME_PATH:
return &internal_uri->parser->property_handler.path;
case PHP_URI_PROPERTY_NAME_QUERY:
return &internal_uri->parser->property_handler.query;
case PHP_URI_PROPERTY_NAME_FRAGMENT:
return &internal_uri->parser->property_handler.fragment;
EMPTY_SWITCH_DEFAULT_CASE()
}
}

static zend_string *get_known_string_by_property_name(php_uri_property_name property_name)
{
switch (property_name) {
Expand Down Expand Up @@ -72,10 +49,9 @@ void uri_read_component(INTERNAL_FUNCTION_PARAMETERS, php_uri_property_name prop
uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS);
URI_ASSERT_INITIALIZATION(internal_uri);

const php_uri_property_handler *property_handler = uri_property_handler_from_internal_uri(internal_uri, property_name);
ZEND_ASSERT(property_handler != NULL);
const php_uri_property_handler *property_handler = php_uri_parser_property_handler_by_name(internal_uri->parser, property_name);

if (UNEXPECTED(property_handler->read(internal_uri, component_read_mode, return_value) == FAILURE)) {
if (UNEXPECTED(property_handler->read(internal_uri->uri, component_read_mode, return_value) == FAILURE)) {
zend_throw_error(NULL, "The %s component cannot be retrieved", ZSTR_VAL(get_known_string_by_property_name(property_name)));
RETURN_THROWS();
}
Expand All @@ -96,8 +72,7 @@ static void uri_write_component_ex(INTERNAL_FUNCTION_PARAMETERS, php_uri_propert
* case of an exception being thrown. */
RETVAL_OBJ(new_object);

const php_uri_property_handler *property_handler = uri_property_handler_from_internal_uri(internal_uri, property_name);
ZEND_ASSERT(property_handler != NULL);
const php_uri_property_handler *property_handler = php_uri_parser_property_handler_by_name(internal_uri->parser, property_name);

uri_internal_t *new_internal_uri = uri_internal_from_obj(new_object);
URI_ASSERT_INITIALIZATION(new_internal_uri);
Expand All @@ -109,7 +84,7 @@ static void uri_write_component_ex(INTERNAL_FUNCTION_PARAMETERS, php_uri_propert

zval errors;
ZVAL_UNDEF(&errors);
if (UNEXPECTED(property_handler->write(new_internal_uri, property_zv, &errors) == FAILURE)) {
if (UNEXPECTED(property_handler->write(new_internal_uri->uri, property_zv, &errors) == FAILURE)) {
zval_ptr_dtor(&errors);
RETURN_THROWS();
}
Expand Down
30 changes: 25 additions & 5 deletions ext/uri/php_uri_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,9 @@ typedef enum php_uri_component_read_mode {
PHP_URI_COMPONENT_READ_MODE_NORMALIZED_UNICODE,
} php_uri_component_read_mode;

struct uri_internal_t;
typedef zend_result (*php_uri_property_handler_read)(void *uri, php_uri_component_read_mode read_mode, zval *retval);

typedef zend_result (*php_uri_property_handler_read)(const struct uri_internal_t *internal_uri, php_uri_component_read_mode read_mode, zval *retval);

typedef zend_result (*php_uri_property_handler_write)(struct uri_internal_t *internal_uri, zval *value, zval *errors);
typedef zend_result (*php_uri_property_handler_write)(void *uri, zval *value, zval *errors);

typedef enum php_uri_property_name {
PHP_URI_PROPERTY_NAME_SCHEME,
Expand Down Expand Up @@ -168,7 +166,29 @@ PHPAPI zend_object *php_uri_object_handler_clone(zend_object *object);
#define PHP_URI_PARSER_PHP_PARSE_URL "parse_url"
#define URI_SERIALIZED_PROPERTY_NAME "uri"

const php_uri_property_handler *uri_property_handler_from_internal_uri(const uri_internal_t *internal_uri, php_uri_property_name property_name);
static inline const php_uri_property_handler *php_uri_parser_property_handler_by_name(const php_uri_parser *parser, php_uri_property_name property_name)
{
switch (property_name) {
case PHP_URI_PROPERTY_NAME_SCHEME:
return &parser->property_handler.scheme;
case PHP_URI_PROPERTY_NAME_USERNAME:
return &parser->property_handler.username;
case PHP_URI_PROPERTY_NAME_PASSWORD:
return &parser->property_handler.password;
case PHP_URI_PROPERTY_NAME_HOST:
return &parser->property_handler.host;
case PHP_URI_PROPERTY_NAME_PORT:
return &parser->property_handler.port;
case PHP_URI_PROPERTY_NAME_PATH:
return &parser->property_handler.path;
case PHP_URI_PROPERTY_NAME_QUERY:
return &parser->property_handler.query;
case PHP_URI_PROPERTY_NAME_FRAGMENT:
return &parser->property_handler.fragment;
EMPTY_SWITCH_DEFAULT_CASE()
}
}

void uri_read_component(INTERNAL_FUNCTION_PARAMETERS, php_uri_property_name property_name, php_uri_component_read_mode component_read_mode);
void uri_write_component_str(INTERNAL_FUNCTION_PARAMETERS, php_uri_property_name property_name);
void uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAMETERS, php_uri_property_name property_name);
Expand Down
Loading