Skip to content

Commit 5cf45ba

Browse files
committed
Fix GH-19371: integer overflow in calendar.c
Closes GH-19380.
1 parent aae35f3 commit 5cf45ba

File tree

4 files changed

+90
-1
lines changed

4 files changed

+90
-1
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ PHP NEWS
2121
(ilutov)
2222
. Fixed zend call stack size for macOs/arm64. (David Carlier)
2323

24+
- Calendar:
25+
. Fixed bug GH-19371 (integer overflow in calendar.c). (nielsdos)
26+
2427
- FTP:
2528
. Fix theoretical issues with hrtime() not being available. (nielsdos)
2629

ext/calendar/calendar.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,16 @@ PHP_FUNCTION(cal_days_in_month)
194194
RETURN_THROWS();
195195
}
196196

197+
if (UNEXPECTED(month <= 0 || month > INT32_MAX - 1)) {
198+
zend_argument_value_error(2, "must be between 1 and %d", INT32_MAX - 1);
199+
RETURN_THROWS();
200+
}
201+
202+
if (UNEXPECTED(year > INT32_MAX - 1)) {
203+
zend_argument_value_error(3, "must be less than %d", INT32_MAX - 1);
204+
RETURN_THROWS();
205+
}
206+
197207
calendar = &cal_conversion_table[cal];
198208

199209
sdn_start = calendar->to_jd(year, month, 1);
@@ -239,6 +249,21 @@ PHP_FUNCTION(cal_to_jd)
239249
RETURN_THROWS();
240250
}
241251

252+
if (UNEXPECTED(month <= 0 || month > INT32_MAX - 1)) {
253+
zend_argument_value_error(2, "must be between 1 and %d", INT32_MAX - 1);
254+
RETURN_THROWS();
255+
}
256+
257+
if (UNEXPECTED(ZEND_LONG_EXCEEDS_INT(day))) {
258+
zend_argument_value_error(3, "must be between %d and %d", INT32_MIN, INT32_MAX);
259+
RETURN_THROWS();
260+
}
261+
262+
if (UNEXPECTED(year > INT32_MAX - 1)) {
263+
zend_argument_value_error(4, "must be less than %d", INT32_MAX - 1);
264+
RETURN_THROWS();
265+
}
266+
242267
RETURN_LONG(cal_conversion_table[cal].to_jd(year, month, day));
243268
}
244269
/* }}} */

ext/calendar/tests/cal_days_in_month_error1.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ try {
1212
echo "{$ex->getMessage()}\n";
1313
}
1414
try{
15-
cal_days_in_month(CAL_GREGORIAN,0, 2009);
15+
cal_days_in_month(CAL_GREGORIAN,20, 2009);
1616
} catch (ValueError $ex) {
1717
echo "{$ex->getMessage()}\n";
1818
}

ext/calendar/tests/gh19371.phpt

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
--TEST--
2+
GH-19371 (integer overflow in calendar.c)
3+
--SKIPIF--
4+
<?php if (PHP_INT_SIZE !== 8) die("skip only for 64-bit"); ?>
5+
--EXTENSIONS--
6+
calendar
7+
--FILE--
8+
<?php
9+
10+
try {
11+
echo cal_days_in_month(CAL_GREGORIAN, 12, PHP_INT_MAX);
12+
} catch (ValueError $e) {
13+
echo $e->getMessage(), "\n";
14+
}
15+
try {
16+
echo cal_days_in_month(CAL_GREGORIAN, PHP_INT_MIN, 1);
17+
} catch (ValueError $e) {
18+
echo $e->getMessage(), "\n";
19+
}
20+
try {
21+
echo cal_days_in_month(CAL_GREGORIAN, PHP_INT_MAX, 1);
22+
} catch (ValueError $e) {
23+
echo $e->getMessage(), "\n";
24+
}
25+
26+
try {
27+
echo cal_to_jd(CAL_GREGORIAN, PHP_INT_MIN, 1, 1);
28+
} catch (ValueError $e) {
29+
echo $e->getMessage(), "\n";
30+
}
31+
try {
32+
echo cal_to_jd(CAL_GREGORIAN, PHP_INT_MAX, 1, 1);
33+
} catch (ValueError $e) {
34+
echo $e->getMessage(), "\n";
35+
}
36+
try {
37+
echo cal_to_jd(CAL_GREGORIAN, 1, PHP_INT_MIN, 1);
38+
} catch (ValueError $e) {
39+
echo $e->getMessage(), "\n";
40+
}
41+
try {
42+
echo cal_to_jd(CAL_GREGORIAN, 1, PHP_INT_MAX, 1);
43+
} catch (ValueError $e) {
44+
echo $e->getMessage(), "\n";
45+
}
46+
try {
47+
echo cal_to_jd(CAL_GREGORIAN, 1, 1, PHP_INT_MAX);
48+
} catch (ValueError $e) {
49+
echo $e->getMessage(), "\n";
50+
}
51+
52+
?>
53+
--EXPECT--
54+
cal_days_in_month(): Argument #3 ($year) must be less than 2147483646
55+
cal_days_in_month(): Argument #2 ($month) must be between 1 and 2147483646
56+
cal_days_in_month(): Argument #2 ($month) must be between 1 and 2147483646
57+
cal_to_jd(): Argument #2 ($month) must be between 1 and 2147483646
58+
cal_to_jd(): Argument #2 ($month) must be between 1 and 2147483646
59+
cal_to_jd(): Argument #3 ($day) must be between -2147483648 and 2147483647
60+
cal_to_jd(): Argument #3 ($day) must be between -2147483648 and 2147483647
61+
cal_to_jd(): Argument #4 ($year) must be less than 2147483646

0 commit comments

Comments
 (0)