Commit f541f529 by Olli Etuaho

Fix parsing integers larger than 0x7FFFFFFF

Parsing should accept all values between 0 and 0xFFFFFFFF as specified in ESSL 3.00 section 4.1.3. When a signed literal is parsed, it's interpreted as if it specifies the bit pattern of a two's complement integer. For example, parsing "0xFFFFFFFF" results in -1. Decimal literals behave the same way, so for example parsing "3000000000" results in -1294967296. This change affects parsing of literals in ESSL 1.00 as well. In ESSL 3.00, an out-of-range integer literal now generates a compiler error. Unit tests are added based on examples in the ESSL 3.00 spec and one example in GLSL 4.5 spec that ESSL should match. BUG=541550 TEST=angle_unittests Change-Id: I82f8ef5cfa2881019a3f80d77ff99707d61c000d Reviewed-on: https://chromium-review.googlesource.com/305420Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarCorentin Wallez <cwallez@google.com>
parent e3f3cf7b
......@@ -72,7 +72,7 @@ static int ES2_reserved_ES3_keyword(TParseContext *context, int token);
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 int_constant(TParseContext *context);
static int float_constant(yyscan_t yyscanner);
static int floatsuffix_check(TParseContext* context);
%}
......@@ -321,9 +321,9 @@ O [0-7]
return check_type(yyscanner);
}
0[xX]{H}+ { return int_constant(yyscanner); }
0{O}+ { return int_constant(yyscanner); }
{D}+ { return int_constant(yyscanner); }
0[xX]{H}+ { return int_constant(context); }
0{O}+ { return int_constant(context); }
{D}+ { return int_constant(context); }
0[xX]{H}+[uU] { return uint_constant(context); }
0{O}+[uU] { return uint_constant(context); }
......@@ -478,7 +478,6 @@ int ES2_ident_ES3_keyword(TParseContext *context, int token)
int uint_constant(TParseContext *context)
{
struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
yyscan_t yyscanner = (yyscan_t) context->getScanner();
if (context->getShaderVersion() < 300)
{
......@@ -487,8 +486,8 @@ int uint_constant(TParseContext *context)
return 0;
}
if (!atoi_clamp(yytext, &(yylval->lex.i)))
yyextra->warning(*yylloc, "Integer overflow", yytext, "");
if (!atoi_clamp(yytext, &(yylval->lex.u)))
yyextra->error(*yylloc, "Integer overflow", yytext, "");
return UINTCONSTANT;
}
......@@ -517,11 +516,18 @@ void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* r
context->recover();
}
int int_constant(yyscan_t yyscanner) {
struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
int int_constant(TParseContext *context) {
struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
if (!atoi_clamp(yytext, &(yylval->lex.i)))
yyextra->warning(*yylloc, "Integer overflow", yytext, "");
unsigned int u;
if (!atoi_clamp(yytext, &u))
{
if (context->getShaderVersion() >= 300)
yyextra->error(*yylloc, "Integer overflow", yytext, "");
else
yyextra->warning(*yylloc, "Integer overflow", yytext, "");
}
yylval->lex.i = static_cast<int>(u);
return INTCONSTANT;
}
......
......@@ -1055,7 +1055,7 @@ static int ES2_reserved_ES3_keyword(TParseContext *context, int token);
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 int_constant(TParseContext *context);
static int float_constant(yyscan_t yyscanner);
static int floatsuffix_check(TParseContext* context);
......@@ -1833,15 +1833,15 @@ YY_RULE_SETUP
YY_BREAK
case 178:
YY_RULE_SETUP
{ return int_constant(yyscanner); }
{ return int_constant(context); }
YY_BREAK
case 179:
YY_RULE_SETUP
{ return int_constant(yyscanner); }
{ return int_constant(context); }
YY_BREAK
case 180:
YY_RULE_SETUP
{ return int_constant(yyscanner); }
{ return int_constant(context); }
YY_BREAK
case 181:
YY_RULE_SETUP
......@@ -3313,7 +3313,6 @@ int ES2_ident_ES3_keyword(TParseContext *context, int token)
int uint_constant(TParseContext *context)
{
struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
yyscan_t yyscanner = (yyscan_t) context->getScanner();
if (context->getShaderVersion() < 300)
{
......@@ -3322,8 +3321,8 @@ int uint_constant(TParseContext *context)
return 0;
}
if (!atoi_clamp(yytext, &(yylval->lex.i)))
yyextra->warning(*yylloc, "Integer overflow", yytext, "");
if (!atoi_clamp(yytext, &(yylval->lex.u)))
yyextra->error(*yylloc, "Integer overflow", yytext, "");
return UINTCONSTANT;
}
......@@ -3352,11 +3351,18 @@ void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* r
context->recover();
}
int int_constant(yyscan_t yyscanner) {
struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
int int_constant(TParseContext *context) {
struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
if (!atoi_clamp(yytext, &(yylval->lex.i)))
yyextra->warning(*yylloc, "Integer overflow", yytext, "");
unsigned int u;
if (!atoi_clamp(yytext, &u))
{
if (context->getShaderVersion() >= 300)
yyextra->error(*yylloc, "Integer overflow", yytext, "");
else
yyextra->warning(*yylloc, "Integer overflow", yytext, "");
}
yylval->lex.i = static_cast<int>(u);
return INTCONSTANT;
}
......
......@@ -20,11 +20,11 @@ bool strtof_clamp(const std::string &str, float *value)
return success;
}
bool atoi_clamp(const char *str, int *value)
bool atoi_clamp(const char *str, unsigned int *value)
{
bool success = pp::numeric_lex_int(str, value);
if (!success)
*value = std::numeric_limits<int>::max();
*value = std::numeric_limits<unsigned int>::max();
return success;
}
......
......@@ -20,9 +20,9 @@
// Return false if overflow happens.
bool strtof_clamp(const std::string &str, float *value);
// If overflow happens, clamp the value to INT_MIN or INT_MAX.
// If overflow happens, clamp the value to UINT_MIN or UINT_MAX.
// Return false if overflow happens.
bool atoi_clamp(const char *str, int *value);
bool atoi_clamp(const char *str, unsigned int *value);
class TSymbolTable;
......
......@@ -71,12 +71,19 @@ class ConstantFinder : public TIntermTraverser
bool isEqual(const TConstantUnion &node, const int &value) const
{
return mFaultTolerance >= abs(node.getIConst() - value);
ASSERT(mFaultTolerance < std::numeric_limits<int>::max());
// abs() returns 0 at least on some platforms when the minimum int value is passed in (it
// doesn't have a positive counterpart).
return mFaultTolerance >= abs(node.getIConst() - value) &&
(node.getIConst() - value) != std::numeric_limits<int>::min();
}
bool isEqual(const TConstantUnion &node, const unsigned int &value) const
{
return mFaultTolerance >= abs(static_cast<int>(node.getUConst() - value));
ASSERT(mFaultTolerance < static_cast<unsigned int>(std::numeric_limits<int>::max()));
return static_cast<int>(mFaultTolerance) >=
abs(static_cast<int>(node.getUConst() - value)) &&
static_cast<int>(node.getUConst() - value) != std::numeric_limits<int>::min();
}
bool isEqual(const TConstantUnion &node, const bool &value) const
......@@ -482,3 +489,78 @@ TEST_F(ConstantFoldingTest, Fold3x3MatrixTranspose)
ASSERT_TRUE(constantVectorFoundInAST(result));
}
// Test that 0xFFFFFFFF wraps to -1 when parsed as integer.
// This is featured in the examples of ESSL3 section 4.1.3. ESSL3 section 12.42
// means that any 32-bit unsigned integer value is a valid literal.
TEST_F(ConstantFoldingTest, ParseWrappedHexIntLiteral)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"precision highp int;\n"
"uniform int inInt;\n"
"out vec4 my_Vec;\n"
"void main() {\n"
" const int i = 0xFFFFFFFF;\n"
" my_Vec = vec4(i * inInt);\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(constantFoundInAST(-1));
}
// Test that 3000000000 wraps to -1294967296 when parsed as integer.
// This is featured in the examples of GLSL 4.5, and ESSL behavior should match
// desktop GLSL when it comes to integer parsing.
TEST_F(ConstantFoldingTest, ParseWrappedDecimalIntLiteral)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"precision highp int;\n"
"uniform int inInt;\n"
"out vec4 my_Vec;\n"
"void main() {\n"
" const int i = 3000000000;\n"
" my_Vec = vec4(i * inInt);\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(constantFoundInAST(-1294967296));
}
// Test that 0xFFFFFFFFu is parsed correctly as an unsigned integer literal.
// This is featured in the examples of ESSL3 section 4.1.3. ESSL3 section 12.42
// means that any 32-bit unsigned integer value is a valid literal.
TEST_F(ConstantFoldingTest, ParseMaxUintLiteral)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"precision highp int;\n"
"uniform uint inInt;\n"
"out vec4 my_Vec;\n"
"void main() {\n"
" const uint i = 0xFFFFFFFFu;\n"
" my_Vec = vec4(i * inInt);\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(constantFoundInAST(0xFFFFFFFFu));
}
// Test that unary minus applied to unsigned int is constant folded correctly.
// This is featured in the examples of ESSL3 section 4.1.3. ESSL3 section 12.42
// means that any 32-bit unsigned integer value is a valid literal.
TEST_F(ConstantFoldingTest, FoldUnaryMinusOnUintLiteral)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"precision highp int;\n"
"uniform uint inInt;\n"
"out vec4 my_Vec;\n"
"void main() {\n"
" const uint i = -1u;\n"
" my_Vec = vec4(i * inInt);\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(constantFoundInAST(0xFFFFFFFFu));
}
......@@ -916,3 +916,20 @@ TEST_F(MalformedShaderTest, ArrayValueFromFunctionParameterAsParameter)
FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
}
}
// Test that out-of-range integer literal generates an error in ESSL 3.00.
TEST_F(MalformedShaderTest, OutOfRangeIntegerLiteral)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"precision highp int;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = vec4(0x100000000);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment