#51023 [Com]: ext/filter/tests/046.phpt fails, does not detect int overflow (with -O2 gcc 4.4)

2010-02-25 Thread seanius at debian dot org
 ID:   51023
 Comment by:   seanius at debian dot org
 Reported By:  geissert at debian dot org
 Status:   Open
 Bug Type: Filter related
 Operating System: *
 PHP Version:  5.3SVN-2010-02-12
 New Comment:

Here's the patch i've cobbled together.  in case it doesn't cut/paste
okay, it's also available at:
http://git.debian.org/?p=pkg-php/php.git;a=commitdiff;h=3061d111de130df7388cc78e26b63cc105574775

From: Sean Finney 
Subject: Fix improper signed overflow detection in filter extension

The existing filter code relied on detecting invalid long integers by
examining computed values for wraparound.  This is not defined
behavior
in any C standard, and in fact recent versions of gcc will optimize
out
such checks resulting in invalid code.

This patch therefore changes how the overflow/underflow conditions are
detected, using more reliable arithmetic.  It also fixes another bug,
that
the minimum integer value (-PHP_INT_MAX)-1 could not be detected
properly.

This patch also includes an update to the test case that detects such
overflows, adding much more thorough and descriptive checking.

Bug: http://bugs.php.net/bug.php?id=51023
Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=570287
--- php.orig/ext/filter/logical_filters.c
+++ php/ext/filter/logical_filters.c
@@ -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 @@ static int php_filter_parse_int(const ch
 
/* 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 @@ static int php_filter_parse_int(const ch
 
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;
--- php.orig/ext/filter/tests/046.phpt
+++ php/ext/filter/tests/046.phpt
@@ -4,16 +4,46 @@ Integer overflow
 
 --FILE--
 
---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)


Previous Comments:


[2010-02-23 13:04:48] j...@php.net

See also bug #51008



[2010-02-20 20:56:44] geiss...@php.net

Further investigation revealed that the bug occurs with gcc 4.4 and
optimisation -02. Without optimisation the code still works.




[2010-02-11 23:31:02] geissert at debian dot org

Description:

The filter fails to detect an integer overflow and passes the
FILTER_VALIDATE_INT test. The problem is caused because
php_filter_parse_int uses a long to detect the overflow, which of course
doesn't have the same size of an integer.

This can be fixed by making ctx_value an integer in both
php_filter_parse_int and php_filter_int (and for correctness, not
setting Z_TYPE_P(value) to IS_LONG).


Reproduce code:
---
// the current test:
$s = sprintf("%d", PHP_INT_MAX);
var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT)));

$s = sprintf("%.0f", PHP_INT_MAX+1);
var_dump(filter_var($s, FILTER_VALIDATE_INT));

$s = sprintf("%d", -PHP_INT_MAX);
var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT)));

Expected result:

bool(true)
bool(false)
bool(true)


Actual result:
--
bool(true)
int(-2147483648)
bool(true)





-- 
Edit this bug report at http://bug

#51023 [Com]: ext/filter/tests/046.phpt fails, does not detect int overflow

2010-02-12 Thread geissert at debian dot org
 ID:  51023
 Comment by:  geissert at debian dot org
 Reported By: geissert at debian dot org
 Status:  Feedback
 Bug Type:Filter related
 PHP Version: 5.3.1
 New Comment:

Still present.
What's the point of checking the code myself and describing the bug and
the fix if you are going to ask me to try the latest svn which contains
the same code on the file where the bug occurs?


Previous Comments:


[2010-02-12 16:13:42] j...@php.net

Please try using this snapshot:

  http://snaps.php.net/php5.3-latest.tar.gz
 
For Windows:

  http://windows.php.net/snapshots/





[2010-02-11 23:31:02] geissert at debian dot org

Description:

The filter fails to detect an integer overflow and passes the
FILTER_VALIDATE_INT test. The problem is caused because
php_filter_parse_int uses a long to detect the overflow, which of course
doesn't have the same size of an integer.

This can be fixed by making ctx_value an integer in both
php_filter_parse_int and php_filter_int (and for correctness, not
setting Z_TYPE_P(value) to IS_LONG).


Reproduce code:
---
// the current test:
$s = sprintf("%d", PHP_INT_MAX);
var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT)));

$s = sprintf("%.0f", PHP_INT_MAX+1);
var_dump(filter_var($s, FILTER_VALIDATE_INT));

$s = sprintf("%d", -PHP_INT_MAX);
var_dump(is_long(filter_var($s, FILTER_VALIDATE_INT)));

Expected result:

bool(true)
bool(false)
bool(true)


Actual result:
--
bool(true)
int(-2147483648)
bool(true)





-- 
Edit this bug report at http://bugs.php.net/?id=51023&edit=1