Skip to content

Add some ValueErrors to ext/date #5613

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

Closed
wants to merge 11 commits into from
71 changes: 44 additions & 27 deletions ext/date/php_date.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ PHPAPI timelib_tzinfo *get_timezone_info(void)
tz = guess_timezone(DATE_TIMEZONEDB);
tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB);
if (! tzi) {
php_error_docref(NULL, E_ERROR, "Timezone database is corrupt - this should *never* happen!");
zend_throw_error(NULL, "Timezone database is corrupt. Please file a bug report as this should never happen");
}
return tzi;
}
Expand Down Expand Up @@ -961,7 +961,7 @@ PHP_FUNCTION(idate)

ret = php_idate(ZSTR_VAL(format)[0], ts, 0);
if (ret == -1) {
php_error_docref(NULL, E_WARNING, "Unrecognized date format token.");
php_error_docref(NULL, E_WARNING, "Unrecognized date format token");
RETURN_FALSE;
}
RETURN_LONG(ret);
Expand Down Expand Up @@ -1009,7 +1009,7 @@ PHPAPI zend_long php_parse_date(const char *string, zend_long *now)
PHP_FUNCTION(strtotime)
{
zend_string *times;
int error1, error2;
int parse_error, epoch_does_not_fit_in_zend_long;
timelib_error_container *error;
zend_long preset_ts, ts;
zend_bool preset_ts_is_null = 1;
Expand All @@ -1022,6 +1022,11 @@ PHP_FUNCTION(strtotime)
Z_PARAM_LONG_OR_NULL(preset_ts, preset_ts_is_null)
ZEND_PARSE_PARAMETERS_END();

/* timelib_strtotime() expects the string to not be empty */
if (ZSTR_LEN(times) == 0) {
RETURN_FALSE;
}

tzi = get_timezone_info();

now = timelib_time_ctor();
Expand All @@ -1032,20 +1037,27 @@ PHP_FUNCTION(strtotime)

t = timelib_strtotime(ZSTR_VAL(times), ZSTR_LEN(times), &error,
DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
error1 = error->error_count;
parse_error = error->error_count;
timelib_error_container_dtor(error);
if (parse_error) {
timelib_time_dtor(now);
timelib_time_dtor(t);
RETURN_FALSE;
}

timelib_fill_holes(t, now, TIMELIB_NO_CLONE);
timelib_update_ts(t, tzi);
ts = timelib_date_to_int(t, &error2);
ts = timelib_date_to_int(t, &epoch_does_not_fit_in_zend_long);

timelib_time_dtor(now);
timelib_time_dtor(t);

if (error1 || error2) {
if (epoch_does_not_fit_in_zend_long) {
php_error_docref(NULL, E_WARNING, "Epoch doesn't fit in a PHP integer");
RETURN_FALSE;
} else {
RETURN_LONG(ts);
}

RETURN_LONG(ts);
}
/* }}} */

Expand All @@ -1057,7 +1069,7 @@ PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
timelib_time *now;
timelib_tzinfo *tzi = NULL;
zend_long ts, adjust_seconds = 0;
int error;
int epoch_does_not_fit_in_zend_long;

ZEND_PARSE_PARAMETERS_START(1, 6)
Z_PARAM_LONG(hou)
Expand Down Expand Up @@ -1115,15 +1127,18 @@ PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
}

/* Clean up and return */
ts = timelib_date_to_int(now, &error);
ts += adjust_seconds;
timelib_time_dtor(now);
ts = timelib_date_to_int(now, &epoch_does_not_fit_in_zend_long);

if (error) {
if (epoch_does_not_fit_in_zend_long) {
timelib_time_dtor(now);
php_error_docref(NULL, E_WARNING, "Epoch doesn't fit in a PHP integer");
RETURN_FALSE;
} else {
RETURN_LONG(ts);
}

ts += adjust_seconds;
timelib_time_dtor(now);

RETURN_LONG(ts);
}
/* }}} */

Expand Down Expand Up @@ -1224,7 +1239,6 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
ta.tm_zone = offset->abbr;
#endif
}

Copy link
Member

Choose a reason for hiding this comment

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

nit: don't remove this empty line

/* VS2012 crt has a bug where strftime crash with %z and %Z format when the
initial buffer is too small. See
http://connect.microsoft.com/VisualStudio/feedback/details/759720/vs2012-strftime-crash-with-z-formatting-code */
Expand Down Expand Up @@ -2781,7 +2795,7 @@ static int php_date_modify(zval *object, char *modify, size_t modify_len) /* {{{
dateobj = Z_PHPDATE_P(object);

if (!(dateobj->time)) {
php_error_docref(NULL, E_WARNING, "The DateTime object has not been correctly initialized by its constructor");
zend_throw_error(NULL, "The DateTime object has not been correctly initialized by its constructor");
return 0;
}

Expand Down Expand Up @@ -3309,7 +3323,7 @@ PHP_FUNCTION(date_timestamp_get)
zval *object;
php_date_obj *dateobj;
zend_long timestamp;
int error;
int epoch_does_not_fit_in_zend_long;

if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &object, date_ce_interface) == FAILURE) {
RETURN_THROWS();
Expand All @@ -3318,12 +3332,14 @@ PHP_FUNCTION(date_timestamp_get)
DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
timelib_update_ts(dateobj->time, NULL);

timestamp = timelib_date_to_int(dateobj->time, &error);
if (error) {
RETURN_FALSE;
} else {
RETVAL_LONG(timestamp);
timestamp = timelib_date_to_int(dateobj->time, &epoch_does_not_fit_in_zend_long);

if (epoch_does_not_fit_in_zend_long) {
zend_value_error("Epoch doesn't fit in a PHP integer");
RETURN_THROWS();
}

RETURN_LONG(timestamp);
}
/* }}} */

Expand Down Expand Up @@ -3387,7 +3403,7 @@ PHP_FUNCTION(timezone_open)
php_timezone_obj *tzobj;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(tz)
Z_PARAM_PATH_STR(tz) /* To prevent null bytes */
ZEND_PARSE_PARAMETERS_END();

tzobj = Z_PHPTIMEZONE_P(php_date_instantiate(date_ce_timezone, return_value));
Expand All @@ -3406,7 +3422,7 @@ PHP_METHOD(DateTimeZone, __construct)
zend_error_handling error_handling;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(tz)
Z_PARAM_PATH_STR(tz) /* To prevent null bytes */
ZEND_PARSE_PARAMETERS_END();

zend_replace_error_handling(EH_THROW, NULL, &error_handling);
Expand Down Expand Up @@ -4336,8 +4352,9 @@ PHP_FUNCTION(timezone_identifiers_list)

/* Extra validation */
if (what == PHP_DATE_TIMEZONE_PER_COUNTRY && option_len != 2) {
php_error_docref(NULL, E_NOTICE, "A two-letter ISO 3166-1 compatible country code is expected");
RETURN_FALSE;
zend_argument_value_error(2, "must be a two-letter ISO 3166-1 compatible country code "
"when argument #1 ($timezoneGroup) is DateTimeZone::PER_COUNTRY");
RETURN_THROWS();
}

tzdb = DATE_TIMEZONEDB;
Expand Down
8 changes: 4 additions & 4 deletions ext/date/php_date.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function date_isodate_set(DateTime $object, int $year, int $week, int $day = 1):

function date_timestamp_set(DateTime $object, int $timestamp): DateTime {}

function date_timestamp_get(DateTimeInterface $object): int|false {}
function date_timestamp_get(DateTimeInterface $object): int {}

function timezone_open(string $timezone): DateTimeZone|false {}

Expand All @@ -88,7 +88,7 @@ function timezone_transitions_get(

function timezone_location_get(DateTimeZone $object): array|false {}

function timezone_identifiers_list(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null): array|false {}
function timezone_identifiers_list(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null): array {}

function timezone_abbreviations_list(): array {}

Expand Down Expand Up @@ -230,7 +230,7 @@ public function setISODate(int $year, int $week, int $dayOfWeek = 1) {}
public function setTimestamp(int $timestamp) {}

/**
* @return int|false
* @return int
Copy link
Member

Choose a reason for hiding this comment

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

Now it returns just an "int", can it not be set as a return type on the function (line 236) itself?

* @alias date_timestamp_get
*/
public function getTimestamp() {}
Expand Down Expand Up @@ -282,7 +282,7 @@ public function getTimezone() {}
public function getOffset() {}

/**
* @return int|false
* @return int
Copy link
Member

Choose a reason for hiding this comment

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

ditto

* @alias date_timestamp_get
*/
public function getTimestamp() {}
Expand Down
8 changes: 3 additions & 5 deletions ext/date/php_date_arginfo.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: fee95924adec03c89fdd677ec26bb6eea34d4b3c */
* Stub hash: cb1532309655d85eb2644cdcfbf23063dfa1ddaf */

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0)
Expand Down Expand Up @@ -151,9 +151,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_timestamp_set, 0, 2, DateTim
ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_date_timestamp_get, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
ZEND_END_ARG_INFO()
#define arginfo_date_timestamp_get arginfo_date_offset_get

ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_timezone_open, 0, 1, DateTimeZone, MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, timezone, IS_STRING, 0)
Expand Down Expand Up @@ -184,7 +182,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_timezone_location_get, 0, 1, MAY
ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_timezone_identifiers_list, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_timezone_identifiers_list, 0, 0, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timezoneGroup, IS_LONG, 0, "DateTimeZone::ALL")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, countryCode, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
Expand Down
9 changes: 4 additions & 5 deletions ext/date/tests/005.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,26 @@ $t = mktime(0,0,0, 6, 27, 2006);
var_dump(idate(1,1));
var_dump(idate(""));
var_dump(idate(0));

var_dump(idate("B", $t));
var_dump(idate("[", $t));
var_dump(idate("'"));

echo "Done\n";
?>
--EXPECTF--
Warning: idate(): Unrecognized date format token. in %s on line %d
Warning: idate(): Unrecognized date format token in %s on line %d
bool(false)

Warning: idate(): idate format is one char in %s on line %d
bool(false)

Warning: idate(): Unrecognized date format token. in %s on line %d
Warning: idate(): Unrecognized date format token in %s on line %d
bool(false)
int(41)

Warning: idate(): Unrecognized date format token. in %s on line %d
Warning: idate(): Unrecognized date format token in %s on line %d
bool(false)

Warning: idate(): Unrecognized date format token. in %s on line %d
Warning: idate(): Unrecognized date format token in %s on line %d
bool(false)
Done
4 changes: 3 additions & 1 deletion ext/date/tests/bug41523.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var_dump( $dt = new DateTime('0000-00-00 00:00:00') );
echo $dt->format( DateTime::ISO8601 ), "\n";

?>
--EXPECT--
--EXPECTF--
array(12) {
["year"]=>
int(0)
Expand Down Expand Up @@ -43,6 +43,8 @@ array(12) {
["is_localtime"]=>
bool(false)
}

Warning: strtotime(): Epoch doesn't fit in a PHP integer in %s on line %d
bool(false)
object(DateTime)#1 (3) {
["date"]=>
Expand Down
16 changes: 12 additions & 4 deletions ext/date/tests/bug52062.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ date.timezone=UTC
<?php
$d = new DateTime('@100000000000');
var_dump($d->format('Y-m-d H:i:s U'));
var_dump($d->getTimestamp());
try {
var_dump($d->getTimestamp());
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
var_dump($d->format('U'));

try {
Expand All @@ -19,16 +23,20 @@ try {
echo $e->getMessage(), "\n";
}
var_dump($d->format('Y-m-d H:i:s U'));
var_dump($d->getTimestamp());
try {
var_dump($d->getTimestamp());
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}

$i = new DateInterval('PT100000000000S');
var_dump($i->format('%s'));
?>
--EXPECT--
string(32) "5138-11-16 09:46:40 100000000000"
bool(false)
Epoch doesn't fit in a PHP integer
string(12) "100000000000"
DateTime::setTimestamp(): Argument #1 ($timestamp) must be of type int, float given
string(32) "5138-11-16 09:46:40 100000000000"
bool(false)
Epoch doesn't fit in a PHP integer
string(10) "1215752192"
24 changes: 13 additions & 11 deletions ext/date/tests/bug70277.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ Bug #70277 (new DateTimeZone($foo) is ignoring text after null byte)
--FILE--
<?php
$timezone = "Europe/Zurich\0Foo";
var_dump(timezone_open($timezone));
var_dump(new DateTimeZone($timezone));
try {
var_dump(timezone_open($timezone));
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
try {
var_dump(new DateTimeZone($timezone));
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
?>
--EXPECTF--
Warning: timezone_open(): Timezone must not contain null bytes in %sbug70277.php on line %d
bool(false)

Fatal error: Uncaught Exception: DateTimeZone::__construct(): Timezone must not contain null bytes in %sbug70277.php:%d
Stack trace:
#0 %sbug70277.php(%d): DateTimeZone->__construct('Europe/Zurich\x00F...')
#1 {main}
thrown in %sbug70277.php on line %d
--EXPECT--
timezone_open(): Argument #1 ($timezone) must not contain any null bytes
DateTimeZone::__construct(): Argument #1 ($timezone) must not contain any null bytes
Loading