diff --git a/ext/standard/pack.c b/ext/standard/pack.c index 8736d291fb246..d50e5ec4b548b 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -750,7 +750,16 @@ PHP_FUNCTION(unpack) c = *format; if (c >= '0' && c <= '9') { - repetitions = atoi(format); + errno = 0; + long tmp = strtol(format, NULL, 10); + /* There is not strtoi. We have to check the range ourselves. + * On 32-bit the INT_{MIN,MAX} are useless because long == int, but on 64-bit they do limit us to 32-bit. */ + if (errno || tmp < INT_MIN || tmp > INT_MAX) { + php_error_docref(NULL, E_WARNING, "Type %c: integer overflow", type); + zend_array_destroy(Z_ARR_P(return_value)); + RETURN_FALSE; + } + repetitions = tmp; while (formatlen > 0 && *format >= '0' && *format <= '9') { format++; @@ -800,7 +809,7 @@ PHP_FUNCTION(unpack) case 'h': case 'H': - size = (repetitions > 0) ? (repetitions + (repetitions % 2)) / 2 : repetitions; + size = (repetitions > 0) ? ((unsigned int) repetitions + 1) / 2 : repetitions; repetitions = 1; break; @@ -865,12 +874,6 @@ PHP_FUNCTION(unpack) RETURN_THROWS(); } - if (size != 0 && size != -1 && size < 0) { - php_error_docref(NULL, E_WARNING, "Type %c: integer overflow", type); - zend_array_destroy(Z_ARR_P(return_value)); - RETURN_FALSE; - } - /* Do actual unpacking */ for (i = 0; i != repetitions; i++ ) { diff --git a/ext/standard/tests/strings/gh10940.phpt b/ext/standard/tests/strings/gh10940.phpt new file mode 100644 index 0000000000000..54ba8545f3866 --- /dev/null +++ b/ext/standard/tests/strings/gh10940.phpt @@ -0,0 +1,9 @@ +--TEST-- +Test unpacking at the 32-bit integer limit +--FILE-- + +--EXPECTF-- +Warning: unpack(): Type h: not enough input, need 1073741824, have 12 in %s on line %d