Skip to content

ext/int: IntlTimeZone converting few intl error to exceptions. #13477

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
38 changes: 35 additions & 3 deletions ext/intl/tests/timezone_createEnumeration_error.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,40 @@ intl
<?php
ini_set("intl.error_level", E_WARNING);

var_dump(IntlTimeZone::createEnumeration(array()));
try {
IntlTimeZone::createEnumeration(array());
} catch (TypeError $e) {
echo $e->getMessage() . PHP_EOL;
}

try {
IntlTimeZone::createEnumeration(str_repeat("8192", 1024));
} catch (ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}

try {
IntlTimeZone::createEnumeration(31.9998157);
} catch (ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}

try {
IntlTimeZone::createEnumeration(-2147483649);
} catch (ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
IntlTimeZone::createEnumeration(2147483648);
} catch (ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
?>
--EXPECTF--
Warning: IntlTimeZone::createEnumeration(): invalid argument type in %s on line %d
bool(false)
IntlTimeZone::createEnumeration(): Argument #1 ($countryOrRawOffset) must be of type string|int, array given

Deprecated: Implicit conversion from float INF to int loses precision in %s on line %d

Deprecated: Implicit conversion from float %f to int loses precision in %s on line %d
IntlTimeZone::createEnumeration(): Argument #1 ($countryOrRawOffset) value must be between %s and %s
IntlTimeZone::createEnumeration(): Argument #1 ($countryOrRawOffset) value must be between %s and %s
13 changes: 13 additions & 0 deletions ext/intl/tests/timezone_createTimeZoneIDEnumeration_error.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,20 @@ intl
ini_set("intl.error_level", E_WARNING);

var_dump(IntlTimeZone::createTimeZoneIDEnumeration(-1));

try {
IntlTimeZone::createTimeZoneIDEnumeration(IntlTimeZone::TYPE_ANY, null, -2147483649);
} catch (ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
IntlTimeZone::createTimeZoneIDEnumeration(IntlTimeZone::TYPE_ANY, null, 2147483648);
} catch (ValueError $e) {
echo $e->getMessage();
}
?>
--EXPECTF--
Warning: IntlTimeZone::createTimeZoneIDEnumeration(): bad zone type in %s on line %d
bool(false)
IntlTimeZone::createTimeZoneIDEnumeration(): Argument #3 ($rawOffset) offset must be between %s and %s
IntlTimeZone::createTimeZoneIDEnumeration(): Argument #3 ($rawOffset) offset must be between %s and %s
9 changes: 9 additions & 0 deletions ext/intl/tests/timezone_fromDateTimeZone_error.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,18 @@ intl
<?php
ini_set("intl.error_level", E_WARNING);

$r = new ReflectionClass("DateTimeZone");
try {
IntlTimeZone::fromDateTimeZone($r->newInstanceWithoutConstructor());
} catch (\Error $e) {
echo $e->getMessage(). PHP_EOL;
}

$dt = new DateTime('2012-08-01 00:00:00 WEST');
var_dump(IntlTimeZone::fromDateTimeZone($dt->getTimeZone()));
?>
--EXPECTF--
DateTimeZone object is unconstructed

Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: time zone id 'WEST' extracted from ext/date DateTimeZone not recognized in %s on line %d
NULL
14 changes: 14 additions & 0 deletions ext/intl/tests/timezone_getEquivalentID_error.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,21 @@ intl
ini_set("intl.error_level", E_WARNING);

var_dump(IntlTimeZone::getEquivalentID("foo\x80", 0));

try {
IntlTimeZOne::getEquivalentID("NL", -2147483649);
} catch (ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}

try {
IntlTimeZOne::getEquivalentID("NL", 2147483648);
} catch (ValueError $e) {
echo $e->getMessage();
}
?>
--EXPECTF--
Warning: IntlTimeZone::getEquivalentID(): could not convert time zone id to UTF-16 in %s on line %d
bool(false)
IntlTimeZone::getEquivalentID(): Argument #2 ($offset) index must be between %s and %s
IntlTimeZone::getEquivalentID(): Argument #2 ($offset) index must be between %s and %s
83 changes: 35 additions & 48 deletions ext/intl/timezone/timezone_methods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,7 @@ U_CFUNC PHP_FUNCTION(intltz_from_date_time_zone)

tzobj = Z_PHPTIMEZONE_P(zv_timezone);
if (!tzobj->initialized) {
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
"DateTimeZone object is unconstructed",
0);
zend_throw_error(NULL, "DateTimeZone object is unconstructed");
RETURN_NULL();
}

Expand Down Expand Up @@ -135,55 +133,44 @@ U_CFUNC PHP_FUNCTION(intltz_get_unknown)
U_CFUNC PHP_FUNCTION(intltz_create_enumeration)
{
zval *arg = NULL;
StringEnumeration *se = NULL;
zend_string *args = NULL;
zend_long argl = 0;
StringEnumeration *se = NULL;
intl_error_reset(NULL);

/* double indirection to have the zend engine destroy the new zval that
* results from separation */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg) == FAILURE) {
RETURN_THROWS();
}
ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_LONG(args, argl);
ZEND_PARSE_PARAMETERS_END();

if (arg == NULL || Z_TYPE_P(arg) == IS_NULL) {
if (ZEND_NUM_ARGS() == 0) {
se = TimeZone::createEnumeration();
Comment on lines +146 to 147
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh maybe the first arg should then be string|int|null, sorry didn't realize this at first.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kocsismate do you think the param should be nullable or not? Or is that not really an issue in regards to the RFC about overloaded methods?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh, thanks for spotting this. The argument should be definitely nullable, otherwise it will be overloaded. @devnexen In most of the cases, using ZEND_NUM_ARGS() is a clear sign of an overloaded signature.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I'm wondering how this parameter can be declared with the string|int type? Currently, its phpdoc says IntlTimeZone|string|int|float|null. 🤔

} else if (Z_TYPE_P(arg) == IS_LONG) {
int_offset:
if (UNEXPECTED(Z_LVAL_P(arg) < (zend_long)INT32_MIN ||
Z_LVAL_P(arg) > (zend_long)INT32_MAX)) {
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
"value is out of range", 0);
RETURN_FALSE;
} else {
if (args) {
double dval;
switch (is_numeric_string(ZSTR_VAL(args), ZSTR_LEN(args), &argl, &dval, 0)) {
case IS_DOUBLE:
argl = zend_dval_to_lval(dval);
if (!zend_is_long_compatible(argl, dval)) {
zend_incompatible_double_to_long_error(dval);
}
case IS_LONG:
goto long_value;
default:
se = TimeZone::createEnumeration(ZSTR_VAL(args));
}
} else {
se = TimeZone::createEnumeration((int32_t) Z_LVAL_P(arg));
}
} else if (Z_TYPE_P(arg) == IS_DOUBLE) {
double_offset:
convert_to_long(arg);
goto int_offset;
} else if (Z_TYPE_P(arg) == IS_OBJECT || Z_TYPE_P(arg) == IS_STRING) {
zend_long lval;
double dval;
if (!try_convert_to_string(arg)) {
RETURN_THROWS();
}
switch (is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), &lval, &dval, 0)) {
case IS_DOUBLE:
zval_ptr_dtor(arg);
ZVAL_DOUBLE(arg, dval);
goto double_offset;
case IS_LONG:
zval_ptr_dtor(arg);
ZVAL_LONG(arg, lval);
goto int_offset;
long_value:
if (UNEXPECTED(argl < (zend_long)INT32_MIN || argl > (zend_long)INT32_MAX)) {
zend_argument_value_error(1, "value must be between %d and %d", INT32_MIN, INT32_MAX);
RETURN_THROWS();
} else {
se = TimeZone::createEnumeration((int32_t) argl);
}
}
/* else call string version */
se = TimeZone::createEnumeration(Z_STRVAL_P(arg));
} else {
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
"invalid argument type", 0);
RETURN_FALSE;
}


if (se) {
IntlIterator_from_StringEnumeration(se, return_value);
} else {
Expand Down Expand Up @@ -242,9 +229,8 @@ U_CFUNC PHP_FUNCTION(intltz_create_time_zone_id_enumeration)

if (!arg3isnull) {
if (UNEXPECTED(offset_arg < (zend_long)INT32_MIN || offset_arg > (zend_long)INT32_MAX)) {
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
"offset out of bounds", 0);
RETURN_FALSE;
zend_argument_value_error(3, "offset must be between %d and %d", INT32_MIN, INT32_MAX);
RETURN_THROWS();
}
offset = (int32_t)offset_arg;
offsetp = &offset;
Expand Down Expand Up @@ -349,7 +335,8 @@ U_CFUNC PHP_FUNCTION(intltz_get_equivalent_id)
}

if (UNEXPECTED(index < (zend_long)INT32_MIN || index > (zend_long)INT32_MAX)) {
RETURN_FALSE;
zend_argument_value_error(2, "index must be between %d and %d", INT32_MIN, INT32_MAX);
RETURN_THROWS();
}

UErrorCode status = UErrorCode();
Expand Down