Skip to content

Commit 5b5fc69

Browse files
committed
Add some ValueErrors to ext/date
1 parent f4b4631 commit 5b5fc69

File tree

7 files changed

+112
-69
lines changed

7 files changed

+112
-69
lines changed

ext/date/php_date.c

+41-23
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ PHPAPI timelib_tzinfo *get_timezone_info(void)
553553
tz = guess_timezone(DATE_TIMEZONEDB);
554554
tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB);
555555
if (! tzi) {
556-
php_error_docref(NULL, E_ERROR, "Timezone database is corrupt - this should *never* happen!");
556+
zend_throw_error(NULL, "Timezone database is corrupt. Please file a bug report as this should never happen");
557557
}
558558
return tzi;
559559
}
@@ -952,8 +952,8 @@ PHP_FUNCTION(idate)
952952
ZEND_PARSE_PARAMETERS_END();
953953

954954
if (ZSTR_LEN(format) != 1) {
955-
php_error_docref(NULL, E_WARNING, "idate format is one char");
956-
RETURN_FALSE;
955+
zend_argument_value_error(1, "must be one character");
956+
RETURN_THROWS();
957957
}
958958

959959
if (ts_is_null) {
@@ -962,8 +962,8 @@ PHP_FUNCTION(idate)
962962

963963
ret = php_idate(ZSTR_VAL(format)[0], ts, 0);
964964
if (ret == -1) {
965-
php_error_docref(NULL, E_WARNING, "Unrecognized date format token.");
966-
RETURN_FALSE;
965+
zend_argument_value_error(1, "must be a valid date format token");
966+
RETURN_THROWS();
967967
}
968968
RETURN_LONG(ret);
969969
}
@@ -1024,6 +1024,12 @@ PHP_FUNCTION(strtotime)
10241024
Z_PARAM_LONG_OR_NULL(preset_ts, preset_ts_is_null)
10251025
ZEND_PARSE_PARAMETERS_END();
10261026

1027+
/* timelib_strtotime() expects the string to not be empty */
1028+
if (ZSTR_LEN(times) == 0) {
1029+
zend_argument_value_error(1, "must not be empty");
1030+
RETURN_THROWS();
1031+
}
1032+
10271033
tzi = get_timezone_info();
10281034

10291035
now = timelib_time_ctor();
@@ -1036,18 +1042,22 @@ PHP_FUNCTION(strtotime)
10361042
DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
10371043
error1 = error->error_count;
10381044
timelib_error_container_dtor(error);
1045+
if (error1) {
1046+
timelib_time_dtor(now);
1047+
timelib_time_dtor(t);
1048+
RETURN_FALSE;
1049+
}
1050+
10391051
timelib_fill_holes(t, now, TIMELIB_NO_CLONE);
10401052
timelib_update_ts(t, tzi);
10411053
ts = timelib_date_to_int(t, &error2);
1054+
/* Seconds since epoch must fit in a zend_long */
1055+
ZEND_ASSERT(!error2);
10421056

10431057
timelib_time_dtor(now);
10441058
timelib_time_dtor(t);
10451059

1046-
if (error1 || error2) {
1047-
RETURN_FALSE;
1048-
} else {
1049-
RETURN_LONG(ts);
1050-
}
1060+
RETURN_LONG(ts);
10511061
}
10521062
/* }}} */
10531063

@@ -1118,14 +1128,12 @@ PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
11181128

11191129
/* Clean up and return */
11201130
ts = timelib_date_to_int(now, &error);
1131+
/* Seconds since epoch must fit in a zend_long */
1132+
ZEND_ASSERT(!error);
11211133
ts += adjust_seconds;
11221134
timelib_time_dtor(now);
11231135

1124-
if (error) {
1125-
RETURN_FALSE;
1126-
} else {
1127-
RETURN_LONG(ts);
1128-
}
1136+
RETURN_LONG(ts);
11291137
}
11301138
/* }}} */
11311139

@@ -1185,7 +1193,8 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
11851193
ZEND_PARSE_PARAMETERS_END();
11861194

11871195
if (ZSTR_LEN(format) == 0) {
1188-
RETURN_FALSE;
1196+
zend_argument_value_error(1, "cannot be empty");
1197+
RETURN_THROWS();
11891198
}
11901199

11911200
if (timestamp_is_null) {
@@ -1229,7 +1238,7 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
12291238
ta.tm_zone = offset->abbr;
12301239
#endif
12311240
}
1232-
1241+
// TODO Cleanup as bug is not present anymore? (Need to update link as MS retired connect.microsoft.com)
12331242
/* VS2012 crt has a bug where strftime crash with %z and %Z format when the
12341243
initial buffer is too small. See
12351244
http://connect.microsoft.com/VisualStudio/feedback/details/759720/vs2012-strftime-crash-with-z-formatting-code */
@@ -2806,7 +2815,7 @@ static int php_date_modify(zval *object, char *modify, size_t modify_len) /* {{{
28062815
dateobj = Z_PHPDATE_P(object);
28072816

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

@@ -3382,11 +3391,9 @@ PHP_FUNCTION(date_timestamp_get)
33823391
timelib_update_ts(dateobj->time, NULL);
33833392

33843393
timestamp = timelib_date_to_int(dateobj->time, &error);
3385-
if (error) {
3386-
RETURN_FALSE;
3387-
} else {
3388-
RETVAL_LONG(timestamp);
3389-
}
3394+
/* Seconds since epoch must fit in a zend_long */
3395+
ZEND_ASSERT(!error);
3396+
RETURN_LONG(timestamp);
33903397
}
33913398
/* }}} */
33923399

@@ -3457,6 +3464,11 @@ PHP_FUNCTION(timezone_open)
34573464
Z_PARAM_STR(tz)
34583465
ZEND_PARSE_PARAMETERS_END();
34593466

3467+
if (ZSTR_LEN(tz) != strlen(ZSTR_VAL(tz))) {
3468+
zend_argument_value_error(1, "cannot contain nul bytes");
3469+
RETURN_THROWS();
3470+
}
3471+
34603472
tzobj = Z_PHPTIMEZONE_P(php_date_instantiate(date_ce_timezone, return_value));
34613473
if (SUCCESS != timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz))) {
34623474
zval_ptr_dtor(return_value);
@@ -3478,6 +3490,11 @@ PHP_METHOD(DateTimeZone, __construct)
34783490
Z_PARAM_STR(tz)
34793491
ZEND_PARSE_PARAMETERS_END();
34803492

3493+
if (ZSTR_LEN(tz) != strlen(ZSTR_VAL(tz))) {
3494+
zend_argument_value_error(1, "cannot contain nul bytes");
3495+
RETURN_THROWS();
3496+
}
3497+
34813498
zend_replace_error_handling(EH_THROW, NULL, &error_handling);
34823499
tzobj = Z_PHPTIMEZONE_P(ZEND_THIS);
34833500
timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz));
@@ -4408,6 +4425,7 @@ PHP_FUNCTION(timezone_identifiers_list)
44084425

44094426
/* Extra validation */
44104427
if (what == PHP_DATE_TIMEZONE_PER_COUNTRY && option_len != 2) {
4428+
// Promoto to ValueError?
44114429
php_error_docref(NULL, E_NOTICE, "A two-letter ISO 3166-1 compatible country code is expected");
44124430
RETURN_FALSE;
44134431
}

ext/date/php_date.stub.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@ function strtotime(string $time, ?int $now = null): int|false {}
66

77
function date(string $format, ?int $timestamp = null): string {}
88

9-
function idate(string $format, ?int $timestamp = null): int|false {}
9+
function idate(string $format, ?int $timestamp = null): int {}
1010

1111
function gmdate(string $format, ?int $timestamp = null): string {}
1212

1313
function mktime(
1414
int $hour, ?int $min = null, ?int $sec = null,
15-
?int $mon = null, ?int $day = null, ?int $year = null): int|false {}
15+
?int $mon = null, ?int $day = null, ?int $year = null): int {}
1616

1717
function gmmktime(
1818
int $hour, ?int $min = null, ?int $sec = null,
19-
?int $mon = null, ?int $day = null, ?int $year = null): int|false {}
19+
?int $mon = null, ?int $day = null, ?int $year = null): int {}
2020

2121
function checkdate(int $m, int $d, int $y): bool {}
2222

@@ -73,7 +73,7 @@ function date_isodate_set(DateTime $object, int $year, int $week, int $day = 1):
7373

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

76-
function date_timestamp_get(DateTimeInterface $object): int|false {}
76+
function date_timestamp_get(DateTimeInterface $object): int {}
7777

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

ext/date/php_date_arginfo.h

+3-5
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_date, 0, 1, IS_STRING, 0)
1010
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timestamp, IS_LONG, 1, "null")
1111
ZEND_END_ARG_INFO()
1212

13-
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_idate, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
13+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_idate, 0, 1, IS_LONG, 0)
1414
ZEND_ARG_TYPE_INFO(0, format, IS_STRING, 0)
1515
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timestamp, IS_LONG, 1, "null")
1616
ZEND_END_ARG_INFO()
1717

1818
#define arginfo_gmdate arginfo_date
1919

20-
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mktime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
20+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mktime, 0, 1, IS_LONG, 0)
2121
ZEND_ARG_TYPE_INFO(0, hour, IS_LONG, 0)
2222
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, min, IS_LONG, 1, "null")
2323
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, sec, IS_LONG, 1, "null")
@@ -150,9 +150,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_timestamp_set, 0, 2, DateTim
150150
ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0)
151151
ZEND_END_ARG_INFO()
152152

153-
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_date_timestamp_get, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
154-
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
155-
ZEND_END_ARG_INFO()
153+
#define arginfo_date_timestamp_get arginfo_date_offset_get
156154

157155
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_timezone_open, 0, 1, DateTimeZone, MAY_BE_FALSE)
158156
ZEND_ARG_TYPE_INFO(0, timezone, IS_STRING, 0)

ext/date/tests/005.phpt

+32-20
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,42 @@ date_default_timezone_set('UTC');
66

77
$t = mktime(0,0,0, 6, 27, 2006);
88

9-
var_dump(idate(1,1));
10-
var_dump(idate(""));
11-
var_dump(idate(0));
9+
try {
10+
var_dump(idate(1,1));
11+
} catch (\ValueError $e) {
12+
echo $e->getMessage() . \PHP_EOL;
13+
}
14+
try {
15+
var_dump(idate(""));
16+
} catch (\ValueError $e) {
17+
echo $e->getMessage() . \PHP_EOL;
18+
}
19+
try {
20+
var_dump(idate(0));
21+
} catch (\ValueError $e) {
22+
echo $e->getMessage() . \PHP_EOL;
23+
}
1224

1325
var_dump(idate("B", $t));
14-
var_dump(idate("[", $t));
15-
var_dump(idate("'"));
26+
27+
try {
28+
var_dump(idate("[", $t));
29+
} catch (\ValueError $e) {
30+
echo $e->getMessage() . \PHP_EOL;
31+
}
32+
try {
33+
var_dump(idate("'"));
34+
} catch (\ValueError $e) {
35+
echo $e->getMessage() . \PHP_EOL;
36+
}
1637

1738
echo "Done\n";
1839
?>
19-
--EXPECTF--
20-
Warning: idate(): Unrecognized date format token. in %s on line %d
21-
bool(false)
22-
23-
Warning: idate(): idate format is one char in %s on line %d
24-
bool(false)
25-
26-
Warning: idate(): Unrecognized date format token. in %s on line %d
27-
bool(false)
40+
--EXPECT--
41+
idate(): Argument #1 ($format) must be a valid date format token
42+
idate(): Argument #1 ($format) must be one character
43+
idate(): Argument #1 ($format) must be a valid date format token
2844
int(41)
29-
30-
Warning: idate(): Unrecognized date format token. in %s on line %d
31-
bool(false)
32-
33-
Warning: idate(): Unrecognized date format token. in %s on line %d
34-
bool(false)
45+
idate(): Argument #1 ($format) must be a valid date format token
46+
idate(): Argument #1 ($format) must be a valid date format token
3547
Done

ext/date/tests/009.phpt

+12-4
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,21 @@ date_default_timezone_set('Asia/Jerusalem');
1010

1111
$t = mktime(0,0,0, 6, 27, 2006);
1212

13-
var_dump(strftime(""));
13+
try {
14+
var_dump(strftime(""));
15+
} catch (\ValueError $e) {
16+
echo $e->getMessage() . \PHP_EOL;
17+
}
1418
var_dump(strftime("%a %A %b %B %c %C %d %D %e %g %G %h %H %I %j %m %M %n %p %r %R %S %t %T %u %U %V %W %w %x %X %y %Y %Z %z %%", $t));
1519
var_dump(strftime("%%q %%a", $t));
1620
var_dump(strftime("%q", $t));
1721
var_dump(strftime("blah", $t));
1822

19-
var_dump(gmstrftime(""));
23+
try {
24+
var_dump(gmstrftime(""));
25+
} catch (\ValueError $e) {
26+
echo $e->getMessage() . \PHP_EOL;
27+
}
2028
var_dump(gmstrftime("%a %A %b %B %c %C %d %D %e %g %G %h %H %I %j %m %M %n %p %r %R %S %t %T %u %U %V %W %w %x %X %y %Y %Z %z %%", $t));
2129
var_dump(gmstrftime("%%q %%a", $t));
2230
var_dump(gmstrftime("%q", $t));
@@ -25,13 +33,13 @@ var_dump(gmstrftime("blah", $t));
2533
echo "Done\n";
2634
?>
2735
--EXPECTF--
28-
bool(false)
36+
strftime(): Argument #1 ($format) cannot be empty
2937
string(%d) "Tue Tuesday Jun June Tue Jun 27 00:00:00 2006 %s
3038
%s %"
3139
string(5) "%q %a"
3240
string(%d) "%s"
3341
string(4) "blah"
34-
bool(false)
42+
gmstrftime(): Argument #1 ($format) cannot be empty
3543
string(%d) "Mon Monday Jun June Mon Jun 26 21:00:00 2006 %s
3644
%s %"
3745
string(5) "%q %a"

ext/date/tests/bug70277.phpt

+13-11
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@ Bug #70277 (new DateTimeZone($foo) is ignoring text after null byte)
33
--FILE--
44
<?php
55
$timezone = "Europe/Zurich\0Foo";
6-
var_dump(timezone_open($timezone));
7-
var_dump(new DateTimeZone($timezone));
6+
try {
7+
var_dump(timezone_open($timezone));
8+
} catch (\ValueError $e) {
9+
echo $e->getMessage() . \PHP_EOL;
10+
}
11+
try {
12+
var_dump(new DateTimeZone($timezone));
13+
} catch (\ValueError $e) {
14+
echo $e->getMessage() . \PHP_EOL;
15+
}
816
?>
9-
--EXPECTF--
10-
Warning: timezone_open(): Timezone must not contain null bytes in %sbug70277.php on line %d
11-
bool(false)
12-
13-
Fatal error: Uncaught Exception: DateTimeZone::__construct(): Timezone must not contain null bytes in %sbug70277.php:%d
14-
Stack trace:
15-
#0 %sbug70277.php(%d): DateTimeZone->__construct('Europe/Zurich\x00F...')
16-
#1 {main}
17-
thrown in %sbug70277.php on line %d
17+
--EXPECT--
18+
timezone_open(): Argument #1 ($timezone) cannot contain nul bytes
19+
DateTimeZone::__construct(): Argument #1 ($timezone) cannot contain nul bytes

ext/date/tests/strtotime3-64bit.phpt

+7-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ $strs = array(
3535
);
3636

3737
foreach ($strs as $str) {
38-
$t = strtotime($str, $time);
38+
try {
39+
$t = strtotime($str, $time);
40+
} catch (\ValueError $e) {
41+
echo $e->getMessage() . \PHP_EOL;
42+
continue;
43+
}
3944
if (is_integer($t)) {
4045
var_dump(date(DATE_RFC2822, $t));
4146
} else {
@@ -45,7 +50,7 @@ foreach ($strs as $str) {
4550

4651
?>
4752
--EXPECT--
48-
bool(false)
53+
strtotime(): Argument #1 ($time) must not be empty
4954
bool(false)
5055
string(31) "Thu, 15 Jun 2006 00:00:00 +0100"
5156
string(31) "Fri, 16 Jun 2006 22:49:12 +0100"

0 commit comments

Comments
 (0)