Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ PHP NEWS
string. (Weilin Du)
. Fixed IntlListFormatter::__construct() leaving stale global error state
after successful calls. (Weilin Du)
. Fixed IntlNumberRangeFormatter leaving stale global error state after
successful createFromSkeleton() and format() calls. (Weilin Du)
. Implemented GH-20255 (Add a predefined calendar constant in
IntlDateFormatter for the proleptic gregorian calendar). (David Carlier)
. Added SpoofChecker::areBidiConfusable(). (David Carlier)
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/gh18572.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ try {
}
?>
--EXPECTREGEX--
(Maximum call stack size reached during object comparison|Nesting level too deep - recursive dependency\?)
(Maximum call stack size reached during (object )?comparison|Nesting level too deep - recursive dependency\?)
40 changes: 40 additions & 0 deletions Zend/tests/gh23088.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
--TEST--
GH-23088 (Stack overflow when comparing deeply nested arrays)
--SKIPIF--
<?php
if (ini_get('zend.max_allowed_stack_size') === false) {
die('skip No stack limit support');
}
if (getenv('SKIP_ASAN')) {
die('skip ASAN needs different stack limit setting due to more stack space usage');
}
?>
--INI--
zend.max_allowed_stack_size=256K
--FILE--
<?php

$a = [];
$b = [];

for ($i = 0; $i < 20000; $i++) {
$a = [$a];
$b = [$b];
}

try {
var_dump($a == $b);
} catch (Error $e) {
echo $e->getMessage(), PHP_EOL;
}

try {
var_dump($a === $b);
} catch (Error $e) {
echo $e->getMessage(), PHP_EOL;
}

?>
--EXPECT--
Maximum call stack size reached during comparison
Maximum call stack size reached during comparison
2 changes: 2 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -5916,6 +5916,8 @@ static void zend_compile_static_var_common(zend_string *var_name, zval *value, u
opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, NULL);
opline->op1_type = IS_CV;
opline->op1.var = lookup_cv(var_name);

ZEND_STATIC_ASSERT(sizeof(Bucket) % 8 == 0, "Bucket size not compatible with storing flags in lower three bits");
opline->extended_value = (uint32_t)((char*)value - (char*)CG(active_op_array)->static_variables->arData) | mode;
}
/* }}} */
Expand Down
7 changes: 7 additions & 0 deletions Zend/zend_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -3221,6 +3221,13 @@ ZEND_API int zend_hash_compare(HashTable *ht1, const HashTable *ht2, compare_fun
return 0;
}

#ifdef ZEND_CHECK_STACK_LIMIT
if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) {
zend_throw_error(NULL, "Maximum call stack size reached during comparison");
return ZEND_UNCOMPARABLE;
}
#endif

/* It's enough to protect only one of the arrays.
* The second one may be referenced from the first and this may cause
* false recursion detection.
Expand Down
9 changes: 7 additions & 2 deletions ext/intl/rangeformatter/rangeformatter_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ U_CFUNC PHP_METHOD(IntlNumberRangeFormatter, createFromSkeleton)
zend_long collapse;
zend_long identityFallback;

intl_error_reset(NULL);

ZEND_PARSE_PARAMETERS_START(4,4)
Z_PARAM_STRING(skeleton, skeleton_len)
Z_PARAM_STRING(locale, locale_len)
Expand Down Expand Up @@ -158,7 +160,10 @@ U_CFUNC PHP_METHOD(IntlNumberRangeFormatter, format)
zval *start;
zval *end;

intl_error_reset(NULL);

IntlNumberRangeFormatter_object* obj = Z_INTL_RANGEFORMATTER_P(ZEND_THIS);
intl_error_reset(RANGEFORMATTER_ERROR_P(obj));

ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_NUMBER(start)
Expand All @@ -179,13 +184,13 @@ U_CFUNC PHP_METHOD(IntlNumberRangeFormatter, format)
INTL_G(error_level) = 0;

if (U_FAILURE(error)) {
intl_error_set(NULL, error, "Failed to format number range");
intl_errors_set(RANGEFORMATTER_ERROR_P(obj), error, "Failed to format number range");
}

zend_string *ret = intl_charFromString(result, &error);

if (U_FAILURE(error)) {
intl_error_set(NULL, error, "Failed to convert result to UTF-8");
intl_errors_set(RANGEFORMATTER_ERROR_P(obj), error, "Failed to convert result to UTF-8");
}

INTL_G(use_exceptions) = old_use_exception;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
--TEST--
IntlNumberRangeFormatter resets stale errors
--EXTENSIONS--
intl
--SKIPIF--
<?php
if (version_compare(INTL_ICU_VERSION, '63.0') < 0) {
die('skip for ICU < 63.0');
}
?>
--FILE--
<?php
try {
IntlNumberRangeFormatter::createFromSkeleton(
'invalid skeleton here',
'en_US',
IntlNumberRangeFormatter::COLLAPSE_AUTO,
IntlNumberRangeFormatter::IDENTITY_FALLBACK_RANGE
);
} catch (IntlException $exception) {
var_dump(str_contains(intl_get_error_message(), 'U_NUMBER_SKELETON_SYNTAX_ERROR'));
}

$formatter = IntlNumberRangeFormatter::createFromSkeleton(
'',
'en_US',
IntlNumberRangeFormatter::COLLAPSE_AUTO,
IntlNumberRangeFormatter::IDENTITY_FALLBACK_RANGE
);

var_dump(intl_get_error_code());
var_dump(intl_get_error_message());

try {
IntlNumberRangeFormatter::createFromSkeleton(
'invalid skeleton here',
'en_US',
IntlNumberRangeFormatter::COLLAPSE_AUTO,
IntlNumberRangeFormatter::IDENTITY_FALLBACK_RANGE
);
} catch (IntlException $exception) {
}

$formatter->format(1, 2);

var_dump(intl_get_error_code());
var_dump(intl_get_error_message());
?>
--EXPECT--
bool(true)
int(0)
string(12) "U_ZERO_ERROR"
int(0)
string(12) "U_ZERO_ERROR"
46 changes: 25 additions & 21 deletions ext/uri/php_uri.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,14 @@ static zend_always_inline zval *php_uri_deref(zval *zv)
return zv;
}

#define Z_RFC3986_URI_PROP_SCHEME_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 0))
#define Z_RFC3986_URI_PROP_USERINFO_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 1))
#define Z_RFC3986_URI_PROP_HOST_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 2))
#define Z_RFC3986_URI_PROP_PORT_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 3))
#define Z_RFC3986_URI_PROP_PATH_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 4))
#define Z_RFC3986_URI_PROP_QUERY_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 5))
#define Z_RFC3986_URI_PROP_FRAGMENT_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 6))
#define Z_RFC3986_URI_PROP_SCHEME_DEREF_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 0))
#define Z_RFC3986_URI_PROP_USERINFO_DEREF_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 1))
#define Z_RFC3986_URI_PROP_HOST_DEREF_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 2))
#define Z_RFC3986_URI_PROP_PORT_DEREF_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 3))
#define Z_RFC3986_URI_PROP_PATH_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 4)
#define Z_RFC3986_URI_PROP_PATH_DEREF_P(zv) php_uri_deref(Z_RFC3986_URI_PROP_PATH_P(zv))
#define Z_RFC3986_URI_PROP_QUERY_DEREF_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 5))
#define Z_RFC3986_URI_PROP_FRAGMENT_DEREF_P(zv) php_uri_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 6))

static HashTable *uri_get_debug_properties(php_uri_object *object)
{
Expand Down Expand Up @@ -1069,14 +1070,17 @@ PHP_METHOD(Uri_Rfc3986_UriBuilder, reset)
{
ZEND_PARSE_PARAMETERS_NONE();

convert_to_null(Z_RFC3986_URI_PROP_SCHEME_P(ZEND_THIS));
convert_to_null(Z_RFC3986_URI_PROP_USERINFO_P(ZEND_THIS));
convert_to_null(Z_RFC3986_URI_PROP_HOST_P(ZEND_THIS));
convert_to_null(Z_RFC3986_URI_PROP_PORT_P(ZEND_THIS));
zval_ptr_dtor(Z_RFC3986_URI_PROP_PATH_P(ZEND_THIS));
zend_object *object = Z_OBJ_P(ZEND_THIS);
zval *property = object->properties_table;
const zval *end = property + object->ce->default_properties_count;

while (property != end) {
zend_object_dtor_property(object, property);
ZVAL_NULL(property);
property++;
}

ZVAL_EMPTY_STRING(Z_RFC3986_URI_PROP_PATH_P(ZEND_THIS));
convert_to_null(Z_RFC3986_URI_PROP_QUERY_P(ZEND_THIS));
convert_to_null(Z_RFC3986_URI_PROP_FRAGMENT_P(ZEND_THIS));

RETVAL_COPY(ZEND_THIS);
}
Expand Down Expand Up @@ -1219,13 +1223,13 @@ PHP_METHOD(Uri_Rfc3986_UriBuilder, build)
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(base_url, php_uri_ce_rfc3986_uri)
ZEND_PARSE_PARAMETERS_END();

const zval *scheme = Z_RFC3986_URI_PROP_SCHEME_P(ZEND_THIS);
const zval *userinfo = Z_RFC3986_URI_PROP_USERINFO_P(ZEND_THIS);
const zval *host = Z_RFC3986_URI_PROP_HOST_P(ZEND_THIS);
const zval *port = Z_RFC3986_URI_PROP_PORT_P(ZEND_THIS);
const zval *path = Z_RFC3986_URI_PROP_PATH_P(ZEND_THIS);
const zval *query = Z_RFC3986_URI_PROP_QUERY_P(ZEND_THIS);
const zval *fragment = Z_RFC3986_URI_PROP_FRAGMENT_P(ZEND_THIS);
const zval *scheme = Z_RFC3986_URI_PROP_SCHEME_DEREF_P(ZEND_THIS);
const zval *userinfo = Z_RFC3986_URI_PROP_USERINFO_DEREF_P(ZEND_THIS);
const zval *host = Z_RFC3986_URI_PROP_HOST_DEREF_P(ZEND_THIS);
const zval *port = Z_RFC3986_URI_PROP_PORT_DEREF_P(ZEND_THIS);
const zval *path = Z_RFC3986_URI_PROP_PATH_DEREF_P(ZEND_THIS);
const zval *query = Z_RFC3986_URI_PROP_QUERY_DEREF_P(ZEND_THIS);
const zval *fragment = Z_RFC3986_URI_PROP_FRAGMENT_DEREF_P(ZEND_THIS);

php_uri_parser_rfc3986_uris *base_uris = NULL;
if (base_url != NULL) {
Expand Down