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