]> granicus.if.org Git - php/commitdiff
Code review:
authorDmitry Stogov <dmitry@php.net>
Tue, 26 Dec 2006 09:16:25 +0000 (09:16 +0000)
committerDmitry Stogov <dmitry@php.net>
Tue, 26 Dec 2006 09:16:25 +0000 (09:16 +0000)
  . fixed integer overflow
  . fixed buffer overflow/underflow
  . added more strict IP validation
  . reimplemented float number validation

12 files changed:
ext/filter/filter.c
ext/filter/filter_private.h
ext/filter/logical_filters.c
ext/filter/tests/030.phpt
ext/filter/tests/045.phpt [new file with mode: 0755]
ext/filter/tests/046.phpt [new file with mode: 0755]
ext/filter/tests/047.phpt [new file with mode: 0755]
ext/filter/tests/048.phpt [new file with mode: 0755]
ext/filter/tests/049.phpt [new file with mode: 0755]
ext/filter/tests/050.phpt [new file with mode: 0755]
ext/filter/tests/051.phpt [new file with mode: 0755]
ext/filter/tests/bug7733.phpt

index 6f692787b9957e6704d228df20ac1800fa75383b..6736c23665cc68f3c2cbf23554cbfcce21cb7de8 100644 (file)
@@ -331,6 +331,7 @@ static void php_zval_filter(zval **value, long filter, long flags, zval *options
                if (zend_hash_find(HASH_OF(options), "default", sizeof("default"), (void **)&tmp) == SUCCESS) {
                        **value = **tmp;
                        zval_copy_ctor(*value);
+                       INIT_PZVAL(*value);
                }
        }
 }
@@ -518,7 +519,6 @@ PHP_FUNCTION(filter_has_var)
        long        arg;
        char       *var;
        int         var_len;
-       zval      **tmp;
        zval       *array_ptr = NULL;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &arg, &var, &var_len) == FAILURE) {
@@ -527,7 +527,7 @@ PHP_FUNCTION(filter_has_var)
 
        array_ptr = php_filter_get_storage(arg TSRMLS_CC);
 
-       if (array_ptr && HASH_OF(array_ptr) && zend_hash_find(HASH_OF(array_ptr), var, var_len + 1, (void **)&tmp) == SUCCESS) {
+       if (array_ptr && HASH_OF(array_ptr) && zend_hash_exists(HASH_OF(array_ptr), var, var_len + 1)) {
                RETURN_TRUE;
        }
 
@@ -542,22 +542,27 @@ static void php_filter_call(zval **filtered, long filter, zval **filter_args, co
        char  *charset = NULL;
 
        if (filter_args && Z_TYPE_PP(filter_args) != IS_ARRAY) {
-               convert_to_long_ex(filter_args);
+               long lval;
+
+               PHP_FILTER_GET_LONG_OPT(filter_args, lval);
+
                if (filter != -1) { /* handler for array apply */
                        /* filter_args is the filter_flags */
-                       filter_flags = Z_LVAL_PP(filter_args);
+                       filter_flags = lval;
+
+                       if (!(filter_flags & FILTER_REQUIRE_ARRAY ||  filter_flags & FILTER_FORCE_ARRAY)) {
+                               filter_flags |= FILTER_REQUIRE_SCALAR;
+                       }
                } else {
-                       filter = Z_LVAL_PP(filter_args);
+                       filter = lval;
                }
        } else if (filter_args) {
                if (zend_hash_find(HASH_OF(*filter_args), "filter", sizeof("filter"), (void **)&option) == SUCCESS) {
-                       convert_to_long(*option);
-                       filter = Z_LVAL_PP(option);
+                       PHP_FILTER_GET_LONG_OPT(option, filter);
                }
 
                if (zend_hash_find(HASH_OF(*filter_args), "flags", sizeof("flags"), (void **)&option) == SUCCESS) {
-                       convert_to_long(*option);
-                       filter_flags = Z_LVAL_PP(option);
+                       PHP_FILTER_GET_LONG_OPT(option, filter_flags);
 
                        if (!(filter_flags & FILTER_REQUIRE_ARRAY ||  filter_flags & FILTER_FORCE_ARRAY)) {
                                filter_flags |= FILTER_REQUIRE_SCALAR;
@@ -708,14 +713,15 @@ PHP_FUNCTION(filter_input)
                        if (Z_TYPE_PP(filter_args) == IS_LONG) {
                                filter_flags = Z_LVAL_PP(filter_args);
                        } else if (Z_TYPE_PP(filter_args) == IS_ARRAY && zend_hash_find(HASH_OF(*filter_args), "flags", sizeof("flags"), (void **)&option) == SUCCESS) {
-                               convert_to_long(*option);
-                               filter_flags = Z_LVAL_PP(option);
+                               PHP_FILTER_GET_LONG_OPT(option, filter_flags);
                        } else if (Z_TYPE_PP(filter_args) == IS_ARRAY && 
                                zend_hash_find(HASH_OF(*filter_args), "options", sizeof("options"), (void **)&opt) == SUCCESS &&
+                               Z_TYPE_PP(opt) == IS_ARRAY &&
                                zend_hash_find(HASH_OF(*opt), "default", sizeof("default"), (void **)&def) == SUCCESS
                        ) {
                                *return_value = **def;
                                zval_copy_ctor(return_value);
+                               INIT_PZVAL(return_value);
                                return;
                        }
                }
@@ -728,6 +734,7 @@ PHP_FUNCTION(filter_input)
 
        *return_value = **tmp;
        zval_copy_ctor(return_value);  /* Watch out for empty strings */
+       INIT_PZVAL(return_value);
 
        php_filter_call(&return_value, filter, filter_args, 1, FILTER_REQUIRE_SCALAR TSRMLS_CC);
 }
@@ -751,6 +758,7 @@ PHP_FUNCTION(filter_var)
 
        *return_value = *data;
        zval_copy_ctor(data);
+       INIT_PZVAL(return_value);
 
        php_filter_call(&return_value, filter, filter_args, 1, FILTER_REQUIRE_SCALAR TSRMLS_CC);
 }
@@ -782,8 +790,7 @@ PHP_FUNCTION(filter_input_array)
                        if (Z_TYPE_PP(op) == IS_LONG) {
                                filter_flags = Z_LVAL_PP(op);
                        } else if (Z_TYPE_PP(op) == IS_ARRAY && zend_hash_find(HASH_OF(*op), "flags", sizeof("flags"), (void **)&option) == SUCCESS) {
-                               convert_to_long(*option);
-                               filter_flags = Z_LVAL_PP(option);
+                               PHP_FILTER_GET_LONG_OPT(option, filter_flags);
                        }
                }
                if (filter_flags & FILTER_NULL_ON_FAILURE) {
index d3b0d072586a2adeac404e8cd3d484469c1cfc0a..a5ef11095015f4c7bb8403a49db7bf0ac27c62ea 100644 (file)
        }       \
        return; \
 
-#define PHP_FILTER_TRIM_DEFAULT(p, len, end) { \
-       while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\v' || *p == '\n') { \
+#define PHP_FILTER_TRIM_DEFAULT(p, len) { \
+       while ((len > 0)  && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\v' || *p == '\n')) { \
                p++; \
                len--; \
        } \
-        if (len < 1) { \
-          RETURN_VALIDATION_FAILED \
-        } \
-        start = p; \
-       end = p + len - 1; \
-       while (*end == ' ' || *end == '\t' || *end == '\r' || *end == '\v' || *end == '\n') { \
-           end--; \
+       if (len < 1) { \
+               RETURN_VALIDATION_FAILED \
+       } \
+       while (p[len-1] == ' ' || p[len-1] == '\t' || p[len-1] == '\r' || p[len-1] == '\v' || p[len-1] == '\n') { \
+               len--; \
        } \
-       *(end + 1) = '\0'; \
-       len = (end - p + 1); \
 }
 
+#define PHP_FILTER_GET_LONG_OPT(zv, opt) { \
+       if (Z_TYPE_PP(zv) != IS_LONG) {                                                                      \
+               zval tmp = **zv;                                                                                 \
+               zval_copy_ctor(&tmp);                                                                                    \
+               convert_to_long(&tmp);                                                                                   \
+               opt = Z_LVAL(tmp);                                                                                  \
+       } else {                                                                                                     \
+               opt = Z_LVAL_PP(zv);                                                                        \
+       }                                                                                                            \
+}
 
 #endif /* FILTER_PRIVATE_H */
 
index 74ac21cde3de51a2068e5074a68b3338f468bf9f..18ff5197dcda1483215aa2377d2e13c78808a893 100644 (file)
 #include "ext/standard/url.h"
 #include "ext/pcre/php_pcre.h"
 
+#include "zend_multiply.h"
+
 #if HAVE_ARPA_INET_H
 # include <arpa/inet.h>
 #endif
 
+#define LONG_SIGN_MASK (1L << (8*sizeof(long)-1))
+
 #ifndef INADDR_NONE
 # define INADDR_NONE ((unsigned long int) -1)
 #endif
@@ -39,8 +43,7 @@
        var_name##_set = 0;                                                                                                  \
        if (option_array) {                                                                                                  \
                if (zend_hash_find(HASH_OF(option_array), option_name, sizeof(option_name), (void **) &option_val) == SUCCESS) { \
-                       convert_to_long(*option_val);                                                                                \
-                       var_name = Z_LVAL_PP(option_val);                                                                            \
+                       PHP_FILTER_GET_LONG_OPT(option_val, var_name);                                                          \
                        var_name##_set = 1;                                                                                          \
                }                                                                                                                \
        }
        var_name##_len = 0;                                                                                                  \
        if (option_array) {                                                                                                  \
                if (zend_hash_find(HASH_OF(option_array), option_name, sizeof(option_name), (void **) &option_val) == SUCCESS) { \
-                       convert_to_string(*option_val);                                                                              \
-                       var_name = Z_STRVAL_PP(option_val);                                                                          \
-                       var_name##_set = 1;                                                                                          \
-                       var_name##_len = Z_STRLEN_PP(option_val);                                                                    \
+                       if (Z_TYPE_PP(option_val) == IS_STRING) {                                                                    \
+                               var_name = Z_STRVAL_PP(option_val);                                                                      \
+                               var_name##_len = Z_STRLEN_PP(option_val);                                                                \
+                               var_name##_set = 1;                                                                                      \
+                       }                                                                                                            \
                }                                                                                                                \
        }
 /* }}} */
 #define FORMAT_IPV6    6
 
 static int php_filter_parse_int(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
-       long ctx_value = 0;
+       long ctx_value;
        long sign = 1;
-       int error = 0;
-       const char *end;
+       const char *end = str + str_len;
+       double dval;
+       long overflow;
 
-       end = str + str_len;
-
-       switch(*str) {
+       switch (*str) {
                case '-':
                        sign = -1;
                case '+':
@@ -82,88 +85,79 @@ static int php_filter_parse_int(const char *str, unsigned int str_len, long *ret
        }
 
        /* must start with 1..9*/
-       if (*str >= '1' && *str <= '9') {
-               ctx_value += ((*str) - '0');
-               str++;
+       if (str < end && *str >= '1' && *str <= '9') {
+               ctx_value = ((*(str++)) - '0');
        } else {
                return -1;
        }
 
-       if (str_len == 1 ) {
-               *ret = ctx_value;
-               return 1;
-       }
-
-       while (*str) {
+       while (str < end) {
                if (*str >= '0' && *str <= '9') {
-                       ctx_value *= 10;
-                       ctx_value += ((*str) - '0');
-                       str++;
+                       ZEND_SIGNED_MULTIPLY_LONG(ctx_value, 10, ctx_value, dval, overflow);
+                       if (overflow) {
+                               return -1;
+                       }
+                       ctx_value += ((*(str++)) - '0');
+                       if (ctx_value & LONG_SIGN_MASK) {
+                               return -1;
+                       }
                } else {
-                       error = 1;
-                       break;
+                       return -1;
                }
        }
 
-       /* state "tail" */
-       if (!error && *str == '\0' && str == end) {
-               *ret = ctx_value * sign;
-               return 1;
-       } else {
-               return -1;
-       }
+       *ret = ctx_value * sign;
+       return 1;
 }
 /* }}} */
 
 static int php_filter_parse_octal(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
-       long ctx_value = 0;
-       int error = 0;
+       unsigned long ctx_value = 0;
+       const char *end = str + str_len;
 
-       while (*str) {
+       while (str < end) {
                if (*str >= '0' && *str <= '7') {
-                       ctx_value *= 8;
-                       ctx_value += ((*str) - '0');
-                       str++;
+                       unsigned long n = ((*(str++)) - '0');
+
+                       if ((ctx_value > ((unsigned long)(~(long)0)) / 8) ||
+                               ((ctx_value = ctx_value * 8) > ((unsigned long)(~(long)0)) - n)) {
+                               return -1;
+                       }
+                       ctx_value += n;
                } else {
-                       error = 1;
-                       break;
+                       return -1;
                }
        }
-       if (!error && *str == '\0') {
-               *ret = ctx_value;
-               return 1;
-       } else {
-               return -1;
-       }
+       
+       *ret = (long)ctx_value;
+       return 1;
 }
 /* }}} */
 
 static int php_filter_parse_hex(const char *str, unsigned int str_len, long *ret TSRMLS_DC) { /* {{{ */
-       long ctx_value = 0;
-       int error = 0;
-
-       while (*str) {
-               if ((*str >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'f') || (*str >= 'A' && *str <= 'F')) {
-                       ctx_value *= 16;
-                       if (*str >= '0' && *str <= '9') {
-                               ctx_value += ((*str) - '0');
-                       } else if (*str >= 'a' && *str <= 'f') {
-                               ctx_value += 10 + ((*str) - 'a');
-                       } else if (*str >= 'A' && *str <= 'F') {
-                               ctx_value += 10 + ((*str) - 'A');
-                       }
-                       str++;
+       unsigned long ctx_value = 0;
+       const char *end = str + str_len;
+       unsigned long n;
+
+       while (str < end) {
+               if (*str >= '0' && *str <= '9') {
+                       n = ((*(str++)) - '0');
+               } else if (*str >= 'a' && *str <= 'f') {
+                       n = ((*(str++)) - ('a' - 10));
+               } else if (*str >= 'A' && *str <= 'F') {
+                       n = ((*(str++)) - ('A' - 10));
                } else {
-                       error = 1;
-                       break;
+                       return -1;
                }
+               if ((ctx_value > ((unsigned long)(~(long)0)) / 16) ||
+                       ((ctx_value = ctx_value * 16) > ((unsigned long)(~(long)0)) - n)) {
+                       return -1;
+               }
+               ctx_value += n;
        }
-       if (!error && *str == '\0') {
-               *ret = ctx_value;
-               return 1;
-       } else {
-               return -1;
-       }
+
+       *ret = (long)ctx_value;
+       return 1;
 }
 /* }}} */
 
@@ -175,7 +169,7 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
        int    allow_octal = 0, allow_hex = 0;
        int        len, error = 0;
        long   ctx_value;
-       char *p, *start, *end;
+       char *p;
 
        /* Parse options */
        FETCH_LONG_OPTION(min_range,    "min_range");
@@ -200,12 +194,12 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
        p = Z_STRVAL_P(value);
        ctx_value = 0;
 
-       PHP_FILTER_TRIM_DEFAULT(p, len, end);
+       PHP_FILTER_TRIM_DEFAULT(p, len);
 
        if (*p == '0') {
-               p++;
+               p++; len--;
                if (allow_hex && (*p == 'x' || *p == 'X')) {
-                       p++;
+                       p++; len--;
                        if (php_filter_parse_hex(p, len, &ctx_value TSRMLS_CC) < 0) {
                                error = 1;
                        }
@@ -213,7 +207,7 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
                        if (php_filter_parse_octal(p, len, &ctx_value TSRMLS_CC) < 0) {
                                error = 1;
                        }
-               } else if (len != 1) {
+               } else if (len != 0) {
                        error = 1;
                }
        } else {
@@ -236,34 +230,65 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
 void php_filter_boolean(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
 {
        char *str = Z_STRVAL_P(value);
-       char *start, *end;
        int len = Z_STRLEN_P(value);
+       int ret;
 
-       if (len>0) {
-               PHP_FILTER_TRIM_DEFAULT(str, len, end);
-       } else {
-               RETURN_VALIDATION_FAILED
-       }
+       PHP_FILTER_TRIM_DEFAULT(str, len);
 
        /* returns true for "1", "true", "on" and "yes"
         * returns false for "0", "false", "off", "no", and ""
         * null otherwise. */
-       if ((strncasecmp(str, "true", sizeof("true")) == 0) ||
-               (strncasecmp(str, "yes", sizeof("yes")) == 0) ||
-               (strncasecmp(str, "on", sizeof("on")) == 0) ||
-               (strncmp(str, "1", sizeof("1")) == 0))
-       {
-               zval_dtor(value);
-               ZVAL_BOOL(value, 1);
-       } else if ((strncasecmp(str, "false", sizeof("false")) == 0) ||
-               (strncasecmp(str, "no", sizeof("no")) == 0) ||
-               (strncasecmp(str, "off", sizeof("off")) == 0) ||
-               (strncmp(str, "0", sizeof("0")) == 0))
-       {
-               zval_dtor(value);
-               ZVAL_BOOL(value, 0);
-       } else {
+       switch (len) {
+               case 1:
+                       if (*str == '1') {
+                               ret = 1;
+                       } else if (*str == '0') {
+                               ret = 0;
+                       } else {
+                               ret = -1;
+                       }
+                       break;
+               case 2:
+                       if (strncasecmp(str, "on", 2) == 0) {
+                               ret = 1;
+                       } else if (strncasecmp(str, "no", 2) == 0) {
+                               ret = 0;
+                       } else {
+                               ret = -1;
+                       }
+                       break;
+               case 3:
+                       if (strncasecmp(str, "yes", 3) == 0) {
+                               ret = 1;
+                       } else if (strncasecmp(str, "off", 3) == 0) {
+                               ret = 0;
+                       } else {
+                               ret = -1;
+                       }
+                       break;
+               case 4:
+                       if (strncasecmp(str, "true", 4) == 0) {
+                               ret = 1;
+                       } else {
+                               ret = -1;
+                       }
+                       break;
+               case 5:
+                       if (strncasecmp(str, "false", 5) == 0) {
+                               ret = 0;
+                       } else {
+                               ret = -1;
+                       }
+                       break;
+               default:
+                       ret = -1;
+       }
+
+       if (ret == -1) {        
                RETURN_VALIDATION_FAILED
+       } else {
+               zval_dtor(value);
+               ZVAL_BOOL(value, ret);
        }
 }
 /* }}} */
@@ -271,169 +296,102 @@ void php_filter_boolean(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
 void php_filter_float(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
 {
        int len;
-       char *str, *start, *end;
+       char *str, *end;
+       char *num, *p;
 
        zval **option_val;
        char *decimal;
-       char dec_sep = '\0';
-
-       const char default_decimal[] = ".";
        int decimal_set, decimal_len;
-
+       char dec_sep = '.';
        char tsd_sep[3] = "',.";
 
-       long options_flag;
-       int options_flag_set;
-
-       int sign = 1;
-
-       double ret_val = 0;
-       double factor;
+       long lval;
+       double dval;
 
-       int exp_value = 0, exp_multiply = 1;
+       int first, n;
 
        len = Z_STRLEN_P(value);
-
-       if (len < 1) {
-               RETURN_VALIDATION_FAILED
-       }
-
        str = Z_STRVAL_P(value);
 
-       PHP_FILTER_TRIM_DEFAULT(str, len, end);
-
-       start = str;
-
-       if (len == 1) {
-               if (*str >= '0' && *str <= '9') {
-                       ret_val = (double)*str - '0';
-               } else if (*str == 'E' || *str == 'e') {
-                       ret_val = 0;
-               }
-               zval_dtor(value);
-               Z_TYPE_P(value) = IS_DOUBLE;
-               Z_DVAL_P(value) = ret_val;
-               return;
-       }
+       PHP_FILTER_TRIM_DEFAULT(str, len);
+       end = str + len;
 
        FETCH_STRING_OPTION(decimal, "decimal");
-       FETCH_LONG_OPTION(options_flag, "flags");
 
        if (decimal_set) {
-               if (decimal_len > 1) {
+               if (decimal_len != 1) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "decimal separator must be one char");
+                       RETURN_VALIDATION_FAILED
                } else {
                        dec_sep = *decimal;
                }
-       } else {
-               dec_sep = *default_decimal;
-       }
-
-       if (*str == '-') {
-               sign = -1;
-               str++;
-               start = str;
-       } else if (*str == '+') {
-               sign = 1;
-               str++;
-               start = str;
-       }
-
-       ret_val = 0.0;
-
-       while (*str == '0') {
-               str++;
-       }
-
-       if (*str == dec_sep) {
-               str++;
-               goto stateDot;
        }
 
-       ret_val = 0;
-
-       if (str != start) {
-               str--;
+       num = p = emalloc(len+1);
+       if (str < end && (*str == '+' || *str == '-')) {
+               *p++ = *str++;
        }
-
-       while (*str && *str != dec_sep) {
-               if ((options_flag & FILTER_FLAG_ALLOW_THOUSAND) && (*str == tsd_sep[0] || *str == tsd_sep[1] || *str == tsd_sep[2])) {
-                       str++;
-                       continue;
-               }
-
-               if (*str == 'e' || *str == 'E') {
-                       goto stateExp;
+       first = 1;
+       while (1) {
+               n = 0;
+               while (str < end && *str >= '0' && *str <= '9') {
+                       ++n;
+                       *p++ = *str++;
                }
-
-               if (*str < '0' || *str > '9') {
-                       goto stateError;
-               }
-
-               ret_val *=10; ret_val += (*str - '0');
-               str++;
-       }
-       if (!(*str)) {
-               goto stateT;
-       }
-       str++;
-
-stateDot:
-       factor = 0.1;
-       while (*str) {
-               if (*str == 'e' || *str == 'E') {
-                       goto stateExp;
+               if (str == end || *str == dec_sep || *str == 'e' || *str == 'E') {
+                       if (!first && n != 3) {
+                               goto error;
+                       }
+                       if (*str == dec_sep) {
+                               *p++ = '.';
+                               str++;
+                               while (str < end && *str >= '0' && *str <= '9') {
+                                       *p++ = *str++;
+                               }
+                       }
+                       if (*str == 'e' || *str == 'E') {
+                               *p++ = *str++;
+                               if (str < end && (*str == '+' || *str == '-')) {
+                                       *p++ = *str++;
+                               }
+                               while (str < end && *str >= '0' && *str <= '9') {
+                                       *p++ = *str++;
+                               }
+                       }
+                       break;
                }
-
-               if (*str < '0' || *str > '9') {
-                       goto stateError;
+               if ((flags & FILTER_FLAG_ALLOW_THOUSAND) && (*str == tsd_sep[0] || *str == tsd_sep[1] || *str == tsd_sep[2])) {
+                       if (first?(n < 1 || n > 3):(n != 3)) {
+                               goto error;
+                       }
+                       first = 0;
+                       str++;
+               } else {
+                       goto error;
                }
-
-               ret_val += factor * (*str - '0');
-               factor /= 10;
-               str++;
        }
-       if (!(*str)) {
-               goto stateT;
+       if (str != end) {
+               goto error;
        }
+       *p = 0;
 
-stateExp:
-       str++;
-       switch (*str) {
-               case '-':
-                       exp_multiply = -1;
-                       str++;
+       switch (is_numeric_string(num, p - num, &lval, &dval, 0)) {
+               case IS_LONG:
+                       zval_dtor(value);
+                       Z_TYPE_P(value) = IS_DOUBLE;
+                       Z_DVAL_P(value) = lval;
                        break;
-               case '+':
-                       exp_multiply = 1;
-                       str++;
-       }
-
-       while (*str) {
-               if (*str < '0' || *str > '9') {
-                       goto stateError;
-               }
-               exp_value *= 10;
-               exp_value += ((*str) - '0');
-               str++;
-       }
-
-stateT:
-       if ((str -1) != end) {
-               goto stateError;
-       }
-       if (exp_value) {
-               exp_value *= exp_multiply;
-               ret_val *= pow(10, exp_value);
+               case IS_DOUBLE:
+                       zval_dtor(value);
+                       Z_TYPE_P(value) = IS_DOUBLE;
+                       Z_DVAL_P(value) = dval;
+                       break;
+               default:
+error:
+                       efree(num);
+                       RETURN_VALIDATION_FAILED
        }
-
-       zval_dtor(value);
-       Z_TYPE_P(value) = IS_DOUBLE;
-       Z_DVAL_P(value) = sign * ret_val;
-       return;
-
-stateError:
-       RETURN_VALIDATION_FAILED
+       efree(num);     
 }
 /* }}} */
 
@@ -533,179 +491,95 @@ void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
 
 static int _php_filter_validate_ipv4(char *str, int str_len, int *ip) /* {{{ */
 {
-       unsigned long int i = inet_addr(str);
-       char ip_chk[16];
-       int l;
-
-       if (i == INADDR_NONE) {
-               if (!strcmp(str, "255.255.255.255")) {
-                       ip[0] = ip[1] = ip[2] = ip[3] = 255;
-                       return 1;
-               } else {
+       const char *end = str + str_len;
+       int num, m;
+       int n = 0;
+
+       while (str < end) {
+               if (*str < '0' || *str > '9') {
+                       return 0;
+               }
+               m = 1;
+               num = ((*(str++)) - '0');
+               while (str < end && (*str >= '0' && *str <= '9')) {
+                       num = num * 10 + ((*(str++)) - '0');
+                       if (num > 255 || ++m > 3) {
+                               return 0;
+                       }
+               }
+               ip[n++] = num;
+               if (n == 4) {
+                       return str == end;
+               } else if (str >= end || *(str++) != '.') {
                        return 0;
                }
        }
-       ip[0] = i & 0xFF;
-       ip[1] = (i & 0xFF00) / 256;
-       ip[2] = (i & 0xFF0000) / 256 / 256;
-       ip[3] = (i & 0xFF000000) / 256 / 256 / 256;
-
-       /* make sure that the input does not have any trailing values */
-       l = sprintf(ip_chk, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
-       if (l != str_len || strcmp(ip_chk, str)) {
-               return 0;
-       }
-
-       return 1;
+       return 0;               
 }
 /* }}} */
 
-#define IS_HEX(s) if (!((s >= '0' && s <= '9') || (s >= 'a' && s <= 'f') ||(s >= 'A' && s <= 'F'))) { \
-       return 0; \
-}
-
-#define IPV6_LOOP_IN(str) \
-                       if (*str == ':') { \
-                               if (hexcode_found > 4) {        \
-                                       return -134;                    \
-                               }                                                       \
-                               hexcode_found = 0;                      \
-                               col_fnd++;                                      \
-                       } else {                                                \
-                               IS_HEX(*str);                           \
-                               hexcode_found++;                        \
-                       }
-
-static int _php_filter_validate_ipv6_(char *str, int str_len TSRMLS_DC) /* {{{ */
+static int _php_filter_validate_ipv6(char *str, int str_len TSRMLS_DC) /* {{{ */
 {
-       int hexcode_found = 0;
-       int compressed_2end = 0;
-       int col_fnd = 0;
-       char *start = str;
-       char *compressed = NULL, *t = str;
-       char *s2 = NULL, *ipv4=NULL;
+       int compressed = 0;
+       int blocks = 8;
+       int n;
+       char *ipv4;
+       char *end;
        int ip4elm[4];
 
        if (!memchr(str, ':', str_len)) {
                return 0;
        }
 
-       /* Check for compressed expression. only one is allowed */
-       compressed = php_memnstr(str, "::", sizeof("::")-1, str+str_len);
-       if (compressed) {
-               s2 = php_memnstr(compressed+1, "::", sizeof("::")-1, str + str_len);
-               if (s2) {
-                       return 0;
-               }
-       }
-
        /* check for bundled IPv4 */
        ipv4 = memchr(str, '.', str_len);
-
        if (ipv4) {
-               while (*ipv4 != ':' && ipv4 >= start) {
+               while (ipv4 > str && *(ipv4-1) != ':') {
                        ipv4--;
                }
 
-               /* ::w.x.y.z */
-               if (compressed && ipv4 == (compressed + 1)) {
-                       compressed_2end = 1;
-               }
-               ipv4++;
-
-               if (!_php_filter_validate_ipv4(ipv4, (str + str_len - ipv4), ip4elm)) {
+               if (!_php_filter_validate_ipv4(ipv4, (str_len - (ipv4 - str)), ip4elm)) {
                        return 0;
                }
-
-               if (compressed_2end) {
-                       return 1;
+               str_len = (ipv4 - str) - 1;
+               if (str_len == 1) {
+                       return *str == ':';
                }
+               blocks = 6;
        }
 
-       if (!compressed) {
-               char *end;
-               if (ipv4) {
-                       end = ipv4 - 1;
-               } else {
-                       end = str + str_len;
-               }
-
-               while (*str && str <= end) {
-                       IPV6_LOOP_IN(str);
-                       str++;
-               }
-
-               if (!ipv4) {
-                       if (col_fnd != 7) {
-                               return 0;
-                       } else {
-                               return 1;
-                       }
-               } else {
-                       if (col_fnd != 6) {
-                               return -1230;
-                       } else {
-                               return 1;
-                       }
-               }
-       } else {
-               if (!ipv4) {
-                       t = compressed - 1;
-                       while (t >= start) {
-                               IPV6_LOOP_IN(t);
-                               t--;
-                       }
-
-                       if (hexcode_found > 4) {
-                               return 0;
-                       }
-
-                       t = compressed + 2;
-                       hexcode_found = 0;
-                       while (*t) {
-                               IPV6_LOOP_IN(t);
-                               t++;
-                       }
-
-                       if (hexcode_found > 4) {
-                               return 0;
-                       }
-
-                       if (col_fnd > 6) {
-                               return 0;
-                       } else {
-                               return 1;
-                       }
-               } else {
-                       /* ipv4 part always at the end */
-                       t = ipv4 - 1;
-                       while (t >= (compressed + 2)) {
-                               IPV6_LOOP_IN(t);
-                               t--;
-                       }
-
-                       if (hexcode_found > 4) {
-                               return 0;
-                       }
-
-                       hexcode_found = 0;
-                       t = compressed - 1;
-                       while (t >= start) {
-                               IPV6_LOOP_IN(t);
-                               t--;
-                       }
-                       if (hexcode_found > 4) {
+       end = str + str_len;
+       while (str < end) {
+               if (*str == ':') {
+                       if (--blocks == 0) {
                                return 0;
-                       }
-
-                       if (col_fnd > 6) {
+                       }                       
+                       if (++str >= end) {
                                return 0;
-                       } else {
-                               return 1;
                        }
+                       if (*str == ':') {
+                               if (compressed || --blocks == 0) {
+                                       return 0;
+                               }                       
+                               if (++str == end) {
+                                       return 1;
+                               }
+                               compressed = 1;
+                       }                               
+               }
+               n = 0;
+               while ((str < end) &&
+                      ((*str >= '0' && *str <= '9') ||
+                       (*str >= 'a' && *str <= 'f') ||
+                       (*str >= 'A' && *str <= 'F'))) {
+                       n++;
+                       str++;
+               }
+               if (n < 1 || n > 4) {
+                       return 0;
                }
        }
-       return 0;
+       return (compressed || blocks == 1);
 }
 /* }}} */
 
@@ -770,7 +644,7 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
                case FORMAT_IPV6:
                        {
                                int res = 0;
-                               res = _php_filter_validate_ipv6_(str, Z_STRLEN_P(value) TSRMLS_CC);
+                               res = _php_filter_validate_ipv6(str, Z_STRLEN_P(value) TSRMLS_CC);
                                if (res < 1) {
                                        RETURN_VALIDATION_FAILED
                                }
index 3163bb34c0d739a7cd69bfe6bf216d730945370c..d3466f5b42c68c7832d7738753c93f8d6a5c282f 100644 (file)
@@ -21,7 +21,13 @@ $ipv6_test = array(
        "0:0:0:0:0:FFFF:129.144.52.38" => true,
        "0:0:0:0:0:0:13.1.68.3"         => true,
        "::13.1.68.3"                           => true,
-    "::FFFF:129.144.52.38"             => true
+    "::FFFF:129.144.52.38"             => true,
+    "1:2:3:4:5:6::129.144.52.38"       => false,
+    "::1:2:3:4:5:6:129.144.52.38"      => false,
+    "1:2:3::4:5:6:129.144.52.38"       => false,
+    "1:2:3:4:5:6:7:8::"                                => false,
+    "::1:2:3:4:5:6:7:8"                                => false,
+    "1:2:3:4::5:6:7:8"                         => false,
 );
 foreach ($ipv6_test as $ip => $exp) {
        $out = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
diff --git a/ext/filter/tests/045.phpt b/ext/filter/tests/045.phpt
new file mode 100755 (executable)
index 0000000..ad8f47e
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+Options must not be changed by filter_var()
+--SKIPIF--
+<?php if (!extension_loaded("filter")) die("skip"); ?>
+--FILE--
+<?php
+$a = array("flags"=>(string)FILTER_FLAG_ALLOW_HEX, "options" => array("min_range"=>"0", "max_range"=>"1024")); 
+$ret = filter_var("0xff", FILTER_VALIDATE_INT, $a);
+echo ($ret === 255 && $a["options"]["min_range"] === "0")?"ok\n":"bug\n";
+echo ($ret === 255 && $a["options"]["max_range"] === "1024")?"ok\n":"bug\n";
+echo ($ret === 255 && is_string($a["flags"]) && $a["flags"] == FILTER_FLAG_ALLOW_HEX)?"ok\n":"bug\n";
+$a = (string)FILTER_FLAG_ALLOW_HEX;
+$ret = filter_var("0xff", FILTER_VALIDATE_INT, $a);
+echo ($ret === 255 && is_string($a) && $a == FILTER_FLAG_ALLOW_HEX)?"ok\n":"bug\n";
+$a = array("test"=>array("filter"=>(string)FILTER_VALIDATE_INT, "flags"=>(string)FILTER_FLAG_ALLOW_HEX));
+$ret = filter_var_array(array("test"=>"0xff"), $a);
+echo ($ret["test"] === 255 && is_string($a["test"]["filter"]) && $a["test"]["filter"] == FILTER_VALIDATE_INT)?"ok\n":"bug\n";
+echo ($ret["test"] === 255 && is_string($a["test"]["flags"]) && $a["test"]["flags"] == FILTER_FLAG_ALLOW_HEX)?"ok\n":"bug\n";
+$a = array("test"=>(string)FILTER_VALIDATE_INT);
+$ret = filter_var_array(array("test"=>"255"), $a);
+echo ($ret["test"] === 255 && is_string($a["test"]) && $a["test"] == FILTER_VALIDATE_INT)?"ok\n":"bug\n";
+?>
+--EXPECT--
+ok
+ok
+ok
+ok
+ok
+ok
+ok
diff --git a/ext/filter/tests/046.phpt b/ext/filter/tests/046.phpt
new file mode 100755 (executable)
index 0000000..390930d
--- /dev/null
@@ -0,0 +1,23 @@
+--TEST--
+Integer overflow
+--SKIPIF--
+<?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)));
+
+$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)));
+
+$s = sprintf("%.0f", -(PHP_INT_MAX+1));
+var_dump(filter_var($s, FILTER_VALIDATE_INT));
+?>
+--EXPECT--
+bool(true)
+bool(false)
+bool(true)
+bool(false)
diff --git a/ext/filter/tests/047.phpt b/ext/filter/tests/047.phpt
new file mode 100755 (executable)
index 0000000..cc41eab
--- /dev/null
@@ -0,0 +1,37 @@
+--TEST--
+Octal integer overflow
+--SKIPIF--
+<?php if (!extension_loaded("filter")) die("skip"); ?>
+--FILE--
+<?php
+function octal_inc($s) {
+       $len = strlen($s);
+       while ($len > 0) {
+               $len--;
+               if ($s[$len] != '7') {
+                       $s[$len] = $s[$len] + 1;
+                       return $s;
+               }
+               $s[$len] = '0';
+       }
+       return '1'.$s;
+}
+
+
+$s = sprintf("%o", PHP_INT_MAX);
+var_dump(is_long(filter_var('0'.$s, FILTER_VALIDATE_INT, array("flags"=>FILTER_FLAG_ALLOW_OCTAL))));
+
+$s = octal_inc($s);
+var_dump(is_long(filter_var('0'.$s, FILTER_VALIDATE_INT, array("flags"=>FILTER_FLAG_ALLOW_OCTAL))));
+
+$s = sprintf("%o", ~0);
+var_dump(is_long(filter_var('0'.$s, FILTER_VALIDATE_INT, array("flags"=>FILTER_FLAG_ALLOW_OCTAL))));
+
+$s = octal_inc($s);
+var_dump(filter_var('0'.$s, FILTER_VALIDATE_INT, array("flags"=>FILTER_FLAG_ALLOW_OCTAL)));
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(false)
diff --git a/ext/filter/tests/048.phpt b/ext/filter/tests/048.phpt
new file mode 100755 (executable)
index 0000000..92ab690
--- /dev/null
@@ -0,0 +1,41 @@
+--TEST--
+Hex integer overflow
+--SKIPIF--
+<?php if (!extension_loaded("filter")) die("skip"); ?>
+--FILE--
+<?php
+function hex_inc($s) {
+       $len = strlen($s);
+       while ($len > 0) {
+               $len--;
+               if ($s[$len] != 'f') {
+                       if ($s[$len] == '9') {
+                               $s[$len] = 'a';
+                       } else {
+                               $s[$len] = $s[$len] + 1;
+                       }
+                       return $s;
+               }
+               $s[$len] = '0';
+       }
+       return '1'.$s;
+}
+
+
+$s = sprintf("%x", PHP_INT_MAX);
+var_dump(is_long(filter_var('0x'.$s, FILTER_VALIDATE_INT, array("flags"=>FILTER_FLAG_ALLOW_HEX))));
+
+$s = hex_inc($s);
+var_dump(is_long(filter_var('0x'.$s, FILTER_VALIDATE_INT, array("flags"=>FILTER_FLAG_ALLOW_HEX))));
+
+$s = sprintf("%x", ~0);
+var_dump(is_long(filter_var('0x'.$s, FILTER_VALIDATE_INT, array("flags"=>FILTER_FLAG_ALLOW_HEX))));
+
+$s = hex_inc($s);
+var_dump(filter_var('0x'.$s, FILTER_VALIDATE_INT, array("flags"=>FILTER_FLAG_ALLOW_HEX)));
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(false)
diff --git a/ext/filter/tests/049.phpt b/ext/filter/tests/049.phpt
new file mode 100755 (executable)
index 0000000..5a9977b
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+filter_var() and doubles with thousend separators
+--SKIPIF--
+<?php if (!extension_loaded("filter")) die("skip"); ?>
+--FILE--
+<?php
+$test = array(
+       '0'                                                     => 0.0,
+       '12345678900.1234567165'        => 12345678900.1234567165,
+       '1,234,567,890.1234567165'      => 1234567890.1234567165,
+       '-1,234,567,890.1234567165'     => -1234567890.1234567165,
+       '1234,567,890.1234567165'       => false,
+       '1,234,567,89.1234567165'       => false,
+       '1,234,567,8900.1234567165'     => false,
+       '1.234.567.890.1234567165'      => false,
+       '1,234,567,8900.123,456'        => false,
+);
+foreach ($test as $src => $dst) {
+       $out = filter_var($src, FILTER_VALIDATE_FLOAT, array("flags"=>FILTER_FLAG_ALLOW_THOUSAND));
+       if ($dst !== $out) {
+               if ($out === false) {
+                       echo "$src -> false != $dst\n";
+               } elseif ($dst === false) {
+                       echo "$src -> $out != false\n";
+               } else {
+                       echo "$src -> $out != $dst\n";
+               }
+       }
+}
+
+echo "Ok\n";
+?>
+--EXPECT--
+Ok
diff --git a/ext/filter/tests/050.phpt b/ext/filter/tests/050.phpt
new file mode 100755 (executable)
index 0000000..69a269f
--- /dev/null
@@ -0,0 +1,29 @@
+--TEST--
+filter_var() and double overflow/underflow
+--SKIPIF--
+<?php if (!extension_loaded("filter")) die("skip"); ?>
+--FILE--
+<?php
+$test = array(
+       '1e+308'                                        => 1e+308,
+       '1e+309'                                        => false,
+       '1e-323'                                        => 1e-323,
+       '1e-324'                                        => false,
+);
+foreach ($test as $src => $dst) {
+       $out = filter_var($src, FILTER_VALIDATE_FLOAT);
+       if ($dst !== $out) {
+               if ($out === false) {
+                       echo "$src -> false != $dst\n";
+               } elseif ($dst === false) {
+                       echo "$src -> $out != false\n";
+               } else {
+                       echo "$src -> $out != $dst\n";
+               }
+       }
+}
+
+echo "Ok\n";
+?>
+--EXPECT--
+Ok
diff --git a/ext/filter/tests/051.phpt b/ext/filter/tests/051.phpt
new file mode 100755 (executable)
index 0000000..e34289d
--- /dev/null
@@ -0,0 +1,11 @@
+--TEST--
+filter_var() and default values
+--SKIPIF--
+<?php if (!extension_loaded("filter")) die("skip"); ?>
+--FILE--
+<?php
+$tmp = $default = 321;
+var_dump(filter_var("123asd", FILTER_VALIDATE_INT, array("options"=>array("default"=>$default))));
+?>
+--EXPECT--
+int(321)
index 4fe82cc918f42df4ba00d309665bc38f9ff80b22..ab02123907ed54137ccf459d2a17bdbe44469831 100644 (file)
@@ -17,13 +17,13 @@ var_dump($out);
 --EXPECTF--    
 array(5) {
   [0]=>
-  float(0)
+  bool(false)
   [1]=>
-  float(10)
+  bool(false)
   [2]=>
-  float(2)
+  bool(false)
   [3]=>
-  float(0)
+  bool(false)
   [4]=>
-  float(0)
+  bool(false)
 }