Clamp numeric overflow rather than failing with an error

BUG=249086
ANGLEBUG=468
TEST=
R=alokp@chromium.org, kbr@chromium.org

Review URL: https://codereview.appspot.com/13195043
diff --git a/src/common/version.h b/src/common/version.h
index bb8d7c7..1f0c909 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -1,7 +1,7 @@
 #define MAJOR_VERSION 1
 #define MINOR_VERSION 2
 #define BUILD_VERSION 0
-#define BUILD_REVISION 2441
+#define BUILD_REVISION 2442
 
 #define STRINGIFY(x) #x
 #define MACRO_STRINGIFY(x) STRINGIFY(x)
diff --git a/src/compiler/glslang.l b/src/compiler/glslang.l
index bb23e13..60663f9 100644
--- a/src/compiler/glslang.l
+++ b/src/compiler/glslang.l
@@ -57,6 +57,8 @@
 static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner);
 static int check_type(yyscan_t yyscanner);
 static int reserved_word(yyscan_t yyscanner);
+static int int_constant(yyscan_t yyscanner);
+static int float_constant(yyscan_t yyscanner);
 %}
 
 %option noyywrap nounput never-interactive
@@ -189,13 +191,13 @@
    return check_type(yyscanner);
 }
 
-0[xX]{H}+         { yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
-0{O}+             { yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
-{D}+              { yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+0[xX]{H}+         { return int_constant(yyscanner); }
+0{O}+             { return int_constant(yyscanner); }
+{D}+              { return int_constant(yyscanner); }
 
-{D}+{E}           { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
-{D}+"."{D}*({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
-"."{D}+({E})?     { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+{D}+{E}           { return float_constant(yyscanner); }
+{D}+"."{D}*({E})? { return float_constant(yyscanner); }
+"."{D}+({E})?     { return float_constant(yyscanner); }
 
 "+="            { return ADD_ASSIGN; }
 "-="            { return SUB_ASSIGN; }
@@ -293,6 +295,22 @@
     context->recover();
 }
 
+int int_constant(yyscan_t yyscanner) {
+    struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+    if (!atoi_clamp(yytext, &(yylval->lex.i)))
+        yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+    return INTCONSTANT;
+}
+
+int float_constant(yyscan_t yyscanner) {
+    struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+    if (!atof_clamp(yytext, &(yylval->lex.f)))
+        yyextra->warning(*yylloc, "Float overflow", yytext, "");
+    return FLOATCONSTANT;
+}
+
 int glslang_initialize(TParseContext* context) {
     yyscan_t scanner = NULL;
     if (yylex_init_extra(context, &scanner))
diff --git a/src/compiler/glslang_lex.cpp b/src/compiler/glslang_lex.cpp
index 2b326bd..14d1411 100644
--- a/src/compiler/glslang_lex.cpp
+++ b/src/compiler/glslang_lex.cpp
@@ -802,6 +802,8 @@
 static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner);
 static int check_type(yyscan_t yyscanner);
 static int reserved_word(yyscan_t yyscanner);
+static int int_constant(yyscan_t yyscanner);
+static int float_constant(yyscan_t yyscanner);
 
 #define INITIAL 0
 
@@ -1500,27 +1502,27 @@
 	YY_BREAK
 case 94:
 YY_RULE_SETUP
-{ yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+{ return int_constant(yyscanner); }
 	YY_BREAK
 case 95:
 YY_RULE_SETUP
-{ yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+{ return int_constant(yyscanner); }
 	YY_BREAK
 case 96:
 YY_RULE_SETUP
-{ yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+{ return int_constant(yyscanner); }
 	YY_BREAK
 case 97:
 YY_RULE_SETUP
-{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+{ return float_constant(yyscanner); }
 	YY_BREAK
 case 98:
 YY_RULE_SETUP
-{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+{ return float_constant(yyscanner); }
 	YY_BREAK
 case 99:
 YY_RULE_SETUP
-{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+{ return float_constant(yyscanner); }
 	YY_BREAK
 case 100:
 YY_RULE_SETUP
@@ -2902,6 +2904,22 @@
     context->recover();
 }
 
+int int_constant(yyscan_t yyscanner) {
+    struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+    if (!atoi_clamp(yytext, &(yylval->lex.i)))
+        yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+    return INTCONSTANT;
+}
+
+int float_constant(yyscan_t yyscanner) {
+    struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+    if (!atof_clamp(yytext, &(yylval->lex.f)))
+        yyextra->warning(*yylloc, "Float overflow", yytext, "");
+    return FLOATCONSTANT;
+}
+
 int glslang_initialize(TParseContext* context) {
     yyscan_t scanner = NULL;
     if (yylex_init_extra(context,&scanner))
diff --git a/src/compiler/preprocessor/Preprocessor.cpp b/src/compiler/preprocessor/Preprocessor.cpp
index 1b979f8..4b9e674 100644
--- a/src/compiler/preprocessor/Preprocessor.cpp
+++ b/src/compiler/preprocessor/Preprocessor.cpp
@@ -100,34 +100,6 @@
           case Token::PP_HASH:

             assert(false);

             break;

-          case Token::CONST_INT:

-          {

-            int val = 0;

-            if (!token->iValue(&val))

-            {

-                // Do not mark the token as invalid.

-                // Just emit the diagnostic and reset value to 0.

-                mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW,

-                                           token->location, token->text);

-                token->text.assign("0");

-            }

-            validToken = true;

-            break;

-          }

-          case Token::CONST_FLOAT:

-          {

-            float val = 0;

-            if (!token->fValue(&val))

-            {

-                // Do not mark the token as invalid.

-                // Just emit the diagnostic and reset value to 0.0.

-                mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW,

-                                           token->location, token->text);

-                token->text.assign("0.0");

-            }

-            validToken = true;

-            break;

-          }

           case Token::PP_NUMBER:

             mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER,

                                        token->location, token->text);

diff --git a/src/compiler/util.cpp b/src/compiler/util.cpp
index b46e4d0..ec375a4 100644
--- a/src/compiler/util.cpp
+++ b/src/compiler/util.cpp
@@ -7,6 +7,9 @@
 #include <math.h>
 #include <stdlib.h>
 
+#include <cerrno>
+#include <limits>
+
 #include "util.h"
 
 #ifdef _MSC_VER
@@ -15,19 +18,39 @@
     #include <sstream>
 #endif
 
-double atof_dot(const char *str)
+bool atof_clamp(const char *str, float *value)
 {
+    bool success = true;
 #ifdef _MSC_VER
     _locale_t l = _create_locale(LC_NUMERIC, "C");
-    double result = _atof_l(str, l);
+    double dvalue = _atof_l(str, l);
     _free_locale(l);
-    return result;
+    if (errno == ERANGE || dvalue > std::numeric_limits<float>::max())
+        success = false;
+    else
+        *value = static_cast<float>(dvalue);
 #else
-    double result;
     std::istringstream s(str);
     std::locale l("C");
     s.imbue(l);
-    s >> result;
-    return result;
+    s >> *value;
+    if (s.fail())
+        success = false;
 #endif
+    if (!success)
+        *value = std::numeric_limits<float>::max();
+    return success;
 }
+
+bool atoi_clamp(const char *str, int *value)
+{
+    long int lvalue = strtol(str, 0, 0);
+    if (errno == ERANGE || lvalue > std::numeric_limits<int>::max())
+    {
+        *value = std::numeric_limits<int>::max();
+        return  false;
+    }
+    *value = static_cast<int>(lvalue);
+    return true;
+}
+
diff --git a/src/compiler/util.h b/src/compiler/util.h
index 35288b7..dc69f39 100644
--- a/src/compiler/util.h
+++ b/src/compiler/util.h
@@ -7,15 +7,14 @@
 #ifndef COMPILER_UTIL_H
 #define COMPILER_UTIL_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+// atof_clamp is like atof but
+//   1. it forces C locale, i.e. forcing '.' as decimal point.
+//   2. it clamps the value to -FLT_MAX or FLT_MAX if overflow happens.
+// Return false if overflow happens.
+extern bool atof_clamp(const char *str, float *value);
 
-// atof_dot is like atof but forcing C locale, i.e. forcing '.' as decimal point.
-double atof_dot(const char *str);
-
-#ifdef __cplusplus
-} // end extern "C"
-#endif
+// If overflow happens, clamp the value to INT_MIN or INT_MAX.
+// Return false if overflow happens.
+extern bool atoi_clamp(const char *str, int *value);
 
 #endif // COMPILER_UTIL_H