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/compiler/glslang.l b/src/compiler/glslang.l
index 3f92490..05cb0d6 100644
--- a/src/compiler/glslang.l
+++ b/src/compiler/glslang.l
@@ -61,6 +61,8 @@
 static int ES2_keyword_ES3_reserved(TParseContext *context, int token);
 static int ES2_ident_ES3_keyword(TParseContext *context, int token);
 static int uint_constant(TParseContext *context);
+static int int_constant(yyscan_t yyscanner);
+static int float_constant(yyscan_t yyscanner);
 static int floatsuffix_check(TParseContext* context);
 %}
 
@@ -307,17 +309,17 @@
    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); }
 
 0[xX]{H}+[uU]     { return uint_constant(context); }
 0{O}+[uU]         { return uint_constant(context); }
 {D}+[uU]          { return uint_constant(context); }
 
-{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); }
 
 {D}+{E}[fF]           { return floatsuffix_check(context); }
 {D}+"."{D}*({E})?[fF] { return floatsuffix_check(context); }
@@ -459,8 +461,6 @@
     struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
     yyscan_t yyscanner = (yyscan_t) context->scanner;
 
-    yylval->lex.u = static_cast<unsigned int>(strtol(yytext, 0, 0));
-
     if (context->shaderVersion < 300)
     {
         context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, "");
@@ -468,6 +468,9 @@
         return 0;
     }
 
+    if (!atoi_clamp(yytext, &(yylval->lex.i)))
+        yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+
     return UINTCONSTANT;
 }
 
@@ -475,8 +478,6 @@
 {
     struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
 
-    yylval->lex.f = static_cast<float>(atof_dot(yytext));
-
     if (context->shaderVersion < 300)
     {
         context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext);
@@ -484,6 +485,9 @@
         return 0;
     }
 
+    if (!atof_clamp(yytext, &(yylval->lex.f)))
+        yyextra->warning(*yylloc, "Float overflow", yytext, "");
+
     return(FLOATCONSTANT);
 }
 
@@ -492,6 +496,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 44a41db..4578a1c 100644
--- a/src/compiler/glslang_lex.cpp
+++ b/src/compiler/glslang_lex.cpp
@@ -1020,6 +1020,8 @@
 static int ES2_keyword_ES3_reserved(TParseContext *context, int token);
 static int ES2_ident_ES3_keyword(TParseContext *context, int token);
 static int uint_constant(TParseContext *context);
+static int int_constant(yyscan_t yyscanner);
+static int float_constant(yyscan_t yyscanner);
 static int floatsuffix_check(TParseContext* context);
 
 #define INITIAL 0
@@ -1793,15 +1795,15 @@
 	YY_BREAK
 case 178:
 YY_RULE_SETUP
-{ yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+{ return int_constant(yyscanner); }
 	YY_BREAK
 case 179:
 YY_RULE_SETUP
-{ yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+{ return int_constant(yyscanner); }
 	YY_BREAK
 case 180:
 YY_RULE_SETUP
-{ yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+{ return int_constant(yyscanner); }
 	YY_BREAK
 case 181:
 YY_RULE_SETUP
@@ -1817,15 +1819,15 @@
 	YY_BREAK
 case 184:
 YY_RULE_SETUP
-{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+{ return float_constant(yyscanner); }
 	YY_BREAK
 case 185:
 YY_RULE_SETUP
-{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+{ return float_constant(yyscanner); }
 	YY_BREAK
 case 186:
 YY_RULE_SETUP
-{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+{ return float_constant(yyscanner); }
 	YY_BREAK
 case 187:
 YY_RULE_SETUP
@@ -3261,8 +3263,6 @@
     struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
     yyscan_t yyscanner = (yyscan_t) context->scanner;
 
-    yylval->lex.u = static_cast<unsigned int>(strtol(yytext, 0, 0));
-
     if (context->shaderVersion < 300)
     {
         context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, "");
@@ -3270,6 +3270,9 @@
         return 0;
     }
 
+    if (!atoi_clamp(yytext, &(yylval->lex.i)))
+        yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+
     return UINTCONSTANT;
 }
 
@@ -3277,8 +3280,6 @@
 {
     struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
 
-    yylval->lex.f = static_cast<float>(atof_dot(yytext));
-
     if (context->shaderVersion < 300)
     {
         context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext);
@@ -3286,6 +3287,9 @@
         return 0;
     }
 
+    if (!atof_clamp(yytext, &(yylval->lex.f)))
+        yyextra->warning(*yylloc, "Float overflow", yytext, "");
+
     return(FLOATCONSTANT);
 }
 
@@ -3294,6 +3298,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/ExpressionParser.cpp b/src/compiler/preprocessor/ExpressionParser.cpp
index 67966e9..9813560 100644
--- a/src/compiler/preprocessor/ExpressionParser.cpp
+++ b/src/compiler/preprocessor/ExpressionParser.cpp
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.7.  */
+/* A Bison parser, made by GNU Bison 2.7.1.  */
 
 /* Bison implementation for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.7"
+#define YYBISON_VERSION "2.7.1"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -258,6 +258,14 @@
 # endif
 #endif
 
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later.  */
+# if (! defined __GNUC__ || __GNUC__ < 2 \
+      || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
+#  define __attribute__(Spec) /* empty */
+# endif
+#endif
+
 /* Suppress unused-variable warnings by "using" E.  */
 #if ! defined lint || defined __GNUC__
 # define YYUSE(E) ((void) (E))
@@ -265,6 +273,7 @@
 # define YYUSE(E) /* empty */
 #endif
 
+
 /* Identity function, used to suppress warnings about constant conditions.  */
 #ifndef lint
 # define YYID(N) (N)
@@ -762,11 +771,7 @@
 # else
   YYUSE (yyoutput);
 # endif
-  switch (yytype)
-    {
-      default:
-        break;
-    }
+  YYUSE (yytype);
 }
 
 
@@ -1160,12 +1165,7 @@
     yymsg = "Deleting";
   YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
 
-  switch (yytype)
-    {
-
-      default:
-        break;
-    }
+  YYUSE (yytype);
 }
 
 
diff --git a/src/compiler/preprocessor/Preprocessor.cpp b/src/compiler/preprocessor/Preprocessor.cpp
index 5ffc642..d0f7213 100644
--- a/src/compiler/preprocessor/Preprocessor.cpp
+++ b/src/compiler/preprocessor/Preprocessor.cpp
@@ -95,34 +95,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);
@@ -139,4 +111,3 @@
 }
 
 }  // namespace pp
-
diff --git a/src/compiler/preprocessor/Tokenizer.cpp b/src/compiler/preprocessor/Tokenizer.cpp
index cec5c51..2b687a9 100644
--- a/src/compiler/preprocessor/Tokenizer.cpp
+++ b/src/compiler/preprocessor/Tokenizer.cpp
@@ -18,7 +18,7 @@
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
+#define YY_FLEX_SUBMINOR_VERSION 37
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -64,7 +64,6 @@
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
 
 /* Limits of integral types. */
 #ifndef INT8_MIN
@@ -95,6 +94,8 @@
 #define UINT32_MAX             (4294967295U)
 #endif
 
+#endif /* ! C99 */
+
 #endif /* ! FLEXINT_H */
 
 #ifdef __cplusplus
@@ -185,6 +186,11 @@
 typedef size_t yy_size_t;
 #endif
 
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
 #define EOB_ACT_CONTINUE_SCAN 0
 #define EOB_ACT_END_OF_FILE 1
 #define EOB_ACT_LAST_MATCH 2
@@ -335,7 +341,7 @@
 
 /* Begin user sect3 */
 
-#define ppwrap(n) 1
+#define ppwrap(yyscanner) 1
 #define YY_SKIP_YYWRAP
 
 typedef unsigned char YY_CHAR;
@@ -661,6 +667,10 @@
 
 void ppset_lineno (int line_number ,yyscan_t yyscanner );
 
+int ppget_column  (yyscan_t yyscanner );
+
+void ppset_column (int column_no ,yyscan_t yyscanner );
+
 YYSTYPE * ppget_lval (yyscan_t yyscanner );
 
 void ppset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
@@ -709,7 +719,7 @@
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
 #endif
 
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
@@ -720,7 +730,7 @@
 	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
 		{ \
 		int c = '*'; \
-		yy_size_t n; \
+		size_t n; \
 		for ( n = 0; n < max_size && \
 			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
@@ -1361,7 +1371,7 @@
 			{ /* Not enough room in the buffer - grow it. */
 
 			/* just a shorter name for the current buffer */
-			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
 
 			int yy_c_buf_p_offset =
 				(int) (yyg->yy_c_buf_p - b->yy_ch_buf);
@@ -1496,6 +1506,7 @@
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 	yy_is_jam = (yy_current_state == 97);
 
+	(void)yyg;
 	return yy_is_jam ? 0 : yy_current_state;
 }
 
@@ -1897,8 +1908,8 @@
 
 /** Setup the input buffer state to scan the given bytes. The next call to pplex() will
  * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
  * @param yyscanner The scanner object.
  * @return the newly allocated buffer state object.
  */
@@ -1906,7 +1917,8 @@
 {
 	YY_BUFFER_STATE b;
 	char *buf;
-	yy_size_t n, i;
+	yy_size_t n;
+	yy_size_t i;
     
 	/* Get memory for full buffer, including space for trailing EOB's. */
 	n = _yybytes_len + 2;
@@ -2052,7 +2064,7 @@
 
         /* lineno is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
-           yy_fatal_error( "ppset_lineno called with no buffer" , yyscanner); 
+           YY_FATAL_ERROR( "ppset_lineno called with no buffer" );
     
     yylineno = line_number;
 }
@@ -2067,7 +2079,7 @@
 
         /* column is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
-           yy_fatal_error( "ppset_column called with no buffer" , yyscanner); 
+           YY_FATAL_ERROR( "ppset_column called with no buffer" );
     
     yycolumn = column_no;
 }
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