geissert Sat, 06 Mar 2010 18:54:55 +0000
Revision: http://svn.php.net/viewvc?view=revision&revision=295896
Log:
Detect overflows before they occur in the filter extension (bug #51023)
Thanks to Sean Finney for the patch
Bug: http://bugs.php.net/51023 (Open) ext/filter/tests/046.phpt fails, does not
detect int overflow (with -O2 gcc 4.4)
Changed paths:
U php/php-src/branches/PHP_5_2/ext/filter/logical_filters.c
U php/php-src/branches/PHP_5_2/ext/filter/tests/046.phpt
U php/php-src/branches/PHP_5_3/ext/filter/logical_filters.c
U php/php-src/branches/PHP_5_3/ext/filter/tests/046.phpt
U php/php-src/trunk/ext/filter/logical_filters.c
U php/php-src/trunk/ext/filter/tests/046.phpt
Modified: php/php-src/branches/PHP_5_2/ext/filter/logical_filters.c
===================================================================
--- php/php-src/branches/PHP_5_2/ext/filter/logical_filters.c 2010-03-06 16:55:43 UTC (rev 295895)
+++ php/php-src/branches/PHP_5_2/ext/filter/logical_filters.c 2010-03-06 18:54:55 UTC (rev 295896)
@@ -68,7 +68,7 @@
static int php_filter_parse_int(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
long ctx_value;
- int sign = 0;
+ int sign = 0, digit = 0;
const char *end = str + str_len;
switch (*str) {
@@ -82,7 +82,7 @@
/* must start with 1..9*/
if (str < end && *str >= '1' && *str <= '9') {
- ctx_value = ((*(str++)) - '0');
+ ctx_value = ((sign)?-1:1) * ((*(str++)) - '0');
} else {
return -1;
}
@@ -95,19 +95,18 @@
while (str < end) {
if (*str >= '0' && *str <= '9') {
- ctx_value = (ctx_value * 10) + (*(str++) - '0');
+ digit = (*(str++) - '0');
+ if ( (!sign) && ctx_value <= (LONG_MAX-digit)/10 ) {
+ ctx_value = (ctx_value * 10) + digit;
+ } else if ( sign && ctx_value >= (LONG_MIN+digit)/10) {
+ ctx_value = (ctx_value * 10) - digit;
+ } else {
+ return -1;
+ }
} else {
return -1;
}
}
- if (sign) {
- ctx_value = -ctx_value;
- if (ctx_value > 0) { /* overflow */
- return -1;
- }
- } else if (ctx_value < 0) { /* overflow */
- return -1;
- }
*ret = ctx_value;
return 1;
Modified: php/php-src/branches/PHP_5_2/ext/filter/tests/046.phpt
===================================================================
--- php/php-src/branches/PHP_5_2/ext/filter/tests/046.phpt 2010-03-06 16:55:43 UTC (rev 295895)
+++ php/php-src/branches/PHP_5_2/ext/filter/tests/046.phpt 2010-03-06 18:54:55 UTC (rev 295896)
@@ -4,16 +4,46 @@
<?php if (!extension_loaded("filter")) die("skip"); ?>
--FILE--
<?php
-$s = sprintf("%d", PHP_INT_MAX);
-var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT)));
+$max = sprintf("%d", PHP_INT_MAX);
+switch($max) {
+case "2147483647": /* 32-bit systems */
+ $min = "-2147483648";
+ $overflow = "2147483648";
+ $underflow = "-2147483649";
+ break;
+case "9223372036854775807": /* 64-bit systems */
+ $min = "-9223372036854775808";
+ $overflow = "9223372036854775808";
+ $underflow = "-9223372036854775809";
+ break;
+default:
+ die("failed: unknown value for PHP_MAX_INT");
+ break;
+}
-$s = sprintf("%.0f", PHP_INT_MAX+1);
-var_dump(filter_var($s, FILTER_VALIDATE_INT));
+function test_validation($val, $msg) {
+ $f = filter_var($val, FILTER_VALIDATE_INT);
+ echo "$msg filtered: "; var_dump($f); // filtered value (or false)
+ echo "$msg is_long: "; var_dump(is_long($f)); // test validation
+ echo "$msg equal: "; var_dump($val == $f); // test equality of result
+}
-$s = sprintf("%d", -PHP_INT_MAX);
-var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT)));
+// PHP_INT_MAX
+test_validation($max, "max");
+test_validation($overflow, "overflow");
+test_validation($min, "min");
+test_validation($underflow, "underflow");
?>
---EXPECT--
-bool(true)
-bool(false)
-bool(true)
+--EXPECTF--
+max filtered: int(%d)
+max is_long: bool(true)
+max equal: bool(true)
+overflow filtered: bool(false)
+overflow is_long: bool(false)
+overflow equal: bool(false)
+min filtered: int(-%d)
+min is_long: bool(true)
+min equal: bool(true)
+underflow filtered: bool(false)
+underflow is_long: bool(false)
+underflow equal: bool(false)
Modified: php/php-src/branches/PHP_5_3/ext/filter/logical_filters.c
===================================================================
--- php/php-src/branches/PHP_5_3/ext/filter/logical_filters.c 2010-03-06 16:55:43 UTC (rev 295895)
+++ php/php-src/branches/PHP_5_3/ext/filter/logical_filters.c 2010-03-06 18:54:55 UTC (rev 295896)
@@ -68,7 +68,7 @@
static int php_filter_parse_int(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
long ctx_value;
- int sign = 0;
+ int sign = 0, digit = 0;
const char *end = str + str_len;
switch (*str) {
@@ -82,7 +82,7 @@
/* must start with 1..9*/
if (str < end && *str >= '1' && *str <= '9') {
- ctx_value = ((*(str++)) - '0');
+ ctx_value = ((sign)?-1:1) * ((*(str++)) - '0');
} else {
return -1;
}
@@ -95,19 +95,18 @@
while (str < end) {
if (*str >= '0' && *str <= '9') {
- ctx_value = (ctx_value * 10) + (*(str++) - '0');
+ digit = (*(str++) - '0');
+ if ( (!sign) && ctx_value <= (LONG_MAX-digit)/10 ) {
+ ctx_value = (ctx_value * 10) + digit;
+ } else if ( sign && ctx_value >= (LONG_MIN+digit)/10) {
+ ctx_value = (ctx_value * 10) - digit;
+ } else {
+ return -1;
+ }
} else {
return -1;
}
}
- if (sign) {
- ctx_value = -ctx_value;
- if (ctx_value > 0) { /* overflow */
- return -1;
- }
- } else if (ctx_value < 0) { /* overflow */
- return -1;
- }
*ret = ctx_value;
return 1;
Modified: php/php-src/branches/PHP_5_3/ext/filter/tests/046.phpt
===================================================================
--- php/php-src/branches/PHP_5_3/ext/filter/tests/046.phpt 2010-03-06 16:55:43 UTC (rev 295895)
+++ php/php-src/branches/PHP_5_3/ext/filter/tests/046.phpt 2010-03-06 18:54:55 UTC (rev 295896)
@@ -4,16 +4,46 @@
<?php if (!extension_loaded("filter")) die("skip"); ?>
--FILE--
<?php
-$s = sprintf("%d", PHP_INT_MAX);
-var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT)));
+$max = sprintf("%d", PHP_INT_MAX);
+switch($max) {
+case "2147483647": /* 32-bit systems */
+ $min = "-2147483648";
+ $overflow = "2147483648";
+ $underflow = "-2147483649";
+ break;
+case "9223372036854775807": /* 64-bit systems */
+ $min = "-9223372036854775808";
+ $overflow = "9223372036854775808";
+ $underflow = "-9223372036854775809";
+ break;
+default:
+ die("failed: unknown value for PHP_MAX_INT");
+ break;
+}
-$s = sprintf("%.0f", PHP_INT_MAX+1);
-var_dump(filter_var($s, FILTER_VALIDATE_INT));
+function test_validation($val, $msg) {
+ $f = filter_var($val, FILTER_VALIDATE_INT);
+ echo "$msg filtered: "; var_dump($f); // filtered value (or false)
+ echo "$msg is_long: "; var_dump(is_long($f)); // test validation
+ echo "$msg equal: "; var_dump($val == $f); // test equality of result
+}
-$s = sprintf("%d", -PHP_INT_MAX);
-var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT)));
+// PHP_INT_MAX
+test_validation($max, "max");
+test_validation($overflow, "overflow");
+test_validation($min, "min");
+test_validation($underflow, "underflow");
?>
---EXPECT--
-bool(true)
-bool(false)
-bool(true)
+--EXPECTF--
+max filtered: int(%d)
+max is_long: bool(true)
+max equal: bool(true)
+overflow filtered: bool(false)
+overflow is_long: bool(false)
+overflow equal: bool(false)
+min filtered: int(-%d)
+min is_long: bool(true)
+min equal: bool(true)
+underflow filtered: bool(false)
+underflow is_long: bool(false)
+underflow equal: bool(false)
Modified: php/php-src/trunk/ext/filter/logical_filters.c
===================================================================
--- php/php-src/trunk/ext/filter/logical_filters.c 2010-03-06 16:55:43 UTC (rev 295895)
+++ php/php-src/trunk/ext/filter/logical_filters.c 2010-03-06 18:54:55 UTC (rev 295896)
@@ -68,7 +68,7 @@
static int php_filter_parse_int(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
long ctx_value;
- int sign = 0;
+ int sign = 0, digit = 0;
const char *end = str + str_len;
switch (*str) {
@@ -82,7 +82,7 @@
/* must start with 1..9*/
if (str < end && *str >= '1' && *str <= '9') {
- ctx_value = ((*(str++)) - '0');
+ ctx_value = ((sign)?-1:1) * ((*(str++)) - '0');
} else {
return -1;
}
@@ -95,19 +95,18 @@
while (str < end) {
if (*str >= '0' && *str <= '9') {
- ctx_value = (ctx_value * 10) + (*(str++) - '0');
+ digit = (*(str++) - '0');
+ if ( (!sign) && ctx_value <= (LONG_MAX-digit)/10 ) {
+ ctx_value = (ctx_value * 10) + digit;
+ } else if ( sign && ctx_value >= (LONG_MIN+digit)/10) {
+ ctx_value = (ctx_value * 10) - digit;
+ } else {
+ return -1;
+ }
} else {
return -1;
}
}
- if (sign) {
- ctx_value = -ctx_value;
- if (ctx_value > 0) { /* overflow */
- return -1;
- }
- } else if (ctx_value < 0) { /* overflow */
- return -1;
- }
*ret = ctx_value;
return 1;
Modified: php/php-src/trunk/ext/filter/tests/046.phpt
===================================================================
--- php/php-src/trunk/ext/filter/tests/046.phpt 2010-03-06 16:55:43 UTC (rev 295895)
+++ php/php-src/trunk/ext/filter/tests/046.phpt 2010-03-06 18:54:55 UTC (rev 295896)
@@ -4,16 +4,46 @@
<?php if (!extension_loaded("filter")) die("skip"); ?>
--FILE--
<?php
-$s = sprintf("%d", PHP_INT_MAX);
-var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT)));
+$max = sprintf("%d", PHP_INT_MAX);
+switch($max) {
+case "2147483647": /* 32-bit systems */
+ $min = "-2147483648";
+ $overflow = "2147483648";
+ $underflow = "-2147483649";
+ break;
+case "9223372036854775807": /* 64-bit systems */
+ $min = "-9223372036854775808";
+ $overflow = "9223372036854775808";
+ $underflow = "-9223372036854775809";
+ break;
+default:
+ die("failed: unknown value for PHP_MAX_INT");
+ break;
+}
-$s = sprintf("%.0f", PHP_INT_MAX+1);
-var_dump(filter_var($s, FILTER_VALIDATE_INT));
+function test_validation($val, $msg) {
+ $f = filter_var($val, FILTER_VALIDATE_INT);
+ echo "$msg filtered: "; var_dump($f); // filtered value (or false)
+ echo "$msg is_long: "; var_dump(is_long($f)); // test validation
+ echo "$msg equal: "; var_dump($val == $f); // test equality of result
+}
-$s = sprintf("%d", -PHP_INT_MAX);
-var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT)));
+// PHP_INT_MAX
+test_validation($max, "max");
+test_validation($overflow, "overflow");
+test_validation($min, "min");
+test_validation($underflow, "underflow");
?>
---EXPECT--
-bool(true)
-bool(false)
-bool(true)
+--EXPECTF--
+max filtered: int(%d)
+max is_long: bool(true)
+max equal: bool(true)
+overflow filtered: bool(false)
+overflow is_long: bool(false)
+overflow equal: bool(false)
+min filtered: int(-%d)
+min is_long: bool(true)
+min equal: bool(true)
+underflow filtered: bool(false)
+underflow is_long: bool(false)
+underflow equal: bool(false)
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php