Commit 2e81891c by alokp@chromium.org

Handled the case where int and float are of correct format, but large. The GLSL…

Handled the case where int and float are of correct format, but large. The GLSL spec is not very clear on how integers should be interpreted for expressions. C99 says the expression is of type intmax_t. I am parsing all integers as int except those in expressions, which are being parsed as unsigned int. Review URL: https://codereview.appspot.com/6351051 git-svn-id: https://angleproject.googlecode.com/svn/trunk@1179 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 7adef604
...@@ -48,6 +48,12 @@ std::string Diagnostics::message(ID id) ...@@ -48,6 +48,12 @@ std::string Diagnostics::message(ID id)
return "invalid character"; return "invalid character";
case INVALID_NUMBER: case INVALID_NUMBER:
return "invalid number"; return "invalid number";
case INTEGER_OVERFLOW:
return "integer overflow";
case FLOAT_OVERFLOW:
return "float overflow";
case IDENTIFIER_OVERFLOW:
return "identifier buffer overflow";
case INVALID_EXPRESSION: case INVALID_EXPRESSION:
return "invalid expression"; return "invalid expression";
case DIVISION_BY_ZERO: case DIVISION_BY_ZERO:
......
...@@ -31,6 +31,9 @@ class Diagnostics ...@@ -31,6 +31,9 @@ class Diagnostics
OUT_OF_MEMORY, OUT_OF_MEMORY,
INVALID_CHARACTER, INVALID_CHARACTER,
INVALID_NUMBER, INVALID_NUMBER,
INTEGER_OVERFLOW,
FLOAT_OVERFLOW,
IDENTIFIER_OVERFLOW,
INVALID_EXPRESSION, INVALID_EXPRESSION,
DIVISION_BY_ZERO, DIVISION_BY_ZERO,
EOF_IN_COMMENT, EOF_IN_COMMENT,
......
...@@ -550,7 +550,7 @@ void DirectiveParser::parseError(Token* token) ...@@ -550,7 +550,7 @@ void DirectiveParser::parseError(Token* token)
{ {
assert(getDirective(token) == DIRECTIVE_ERROR); assert(getDirective(token) == DIRECTIVE_ERROR);
std::stringstream stream; std::ostringstream stream;
mTokenizer->lex(token); mTokenizer->lex(token);
while ((token->type != '\n') && (token->type != Token::LAST)) while ((token->type != '\n') && (token->type != Token::LAST))
{ {
...@@ -709,7 +709,12 @@ void DirectiveParser::parseVersion(Token* token) ...@@ -709,7 +709,12 @@ void DirectiveParser::parseVersion(Token* token)
token->location, token->text); token->location, token->text);
valid = false; valid = false;
} }
if (valid) version = atoi(token->text.c_str()); if (valid && !token->iValue(&version))
{
mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
token->location, token->text);
valid = false;
}
break; break;
default: default:
if (valid) if (valid)
...@@ -759,7 +764,12 @@ void DirectiveParser::parseLine(Token* token) ...@@ -759,7 +764,12 @@ void DirectiveParser::parseLine(Token* token)
token->location, token->text); token->location, token->text);
valid = false; valid = false;
} }
if (valid) line = atoi(token->text.c_str()); if (valid && !token->iValue(&line))
{
mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
token->location, token->text);
valid = false;
}
break; break;
case FILE_NUMBER: case FILE_NUMBER:
if (valid && (token->type != Token::CONST_INT)) if (valid && (token->type != Token::CONST_INT))
...@@ -768,7 +778,12 @@ void DirectiveParser::parseLine(Token* token) ...@@ -768,7 +778,12 @@ void DirectiveParser::parseLine(Token* token)
token->location, token->text); token->location, token->text);
valid = false; valid = false;
} }
if (valid) file = atoi(token->text.c_str()); if (valid && !token->iValue(&file))
{
mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
token->location, token->text);
valid = false;
}
break; break;
default: default:
if (valid) if (valid)
......
...@@ -93,7 +93,6 @@ ...@@ -93,7 +93,6 @@
#include "ExpressionParser.h" #include "ExpressionParser.h"
#include <cassert> #include <cassert>
#include <cstdlib>
#include <sstream> #include <sstream>
#include "Diagnostics.h" #include "Diagnostics.h"
...@@ -102,7 +101,6 @@ ...@@ -102,7 +101,6 @@
#if defined(_MSC_VER) #if defined(_MSC_VER)
typedef __int64 YYSTYPE; typedef __int64 YYSTYPE;
#define strtoll _strtoi64
#else #else
#include <stdint.h> #include <stdint.h>
typedef intmax_t YYSTYPE; typedef intmax_t YYSTYPE;
...@@ -469,9 +467,9 @@ static const yytype_int8 yyrhs[] = ...@@ -469,9 +467,9 @@ static const yytype_int8 yyrhs[] =
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ /* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint8 yyrline[] = static const yytype_uint8 yyrline[] =
{ {
0, 87, 87, 94, 95, 98, 101, 104, 107, 110, 0, 85, 85, 92, 93, 96, 99, 102, 105, 108,
113, 116, 119, 122, 125, 128, 131, 134, 137, 140, 111, 114, 117, 120, 123, 126, 129, 132, 135, 138,
153, 166, 169, 172, 175, 178, 181 151, 164, 167, 170, 173, 176, 179
}; };
#endif #endif
...@@ -1552,7 +1550,7 @@ yyreduce: ...@@ -1552,7 +1550,7 @@ yyreduce:
{ {
if ((yyvsp[(3) - (3)]) == 0) { if ((yyvsp[(3) - (3)]) == 0) {
std::stringstream stream; std::ostringstream stream;
stream << (yyvsp[(1) - (3)]) << " % " << (yyvsp[(3) - (3)]); stream << (yyvsp[(1) - (3)]) << " % " << (yyvsp[(3) - (3)]);
std::string text = stream.str(); std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO, context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
...@@ -1569,7 +1567,7 @@ yyreduce: ...@@ -1569,7 +1567,7 @@ yyreduce:
{ {
if ((yyvsp[(3) - (3)]) == 0) { if ((yyvsp[(3) - (3)]) == 0) {
std::stringstream stream; std::ostringstream stream;
stream << (yyvsp[(1) - (3)]) << " / " << (yyvsp[(3) - (3)]); stream << (yyvsp[(1) - (3)]) << " / " << (yyvsp[(3) - (3)]);
std::string text = stream.str(); std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO, context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
...@@ -1846,10 +1844,17 @@ int yylex(YYSTYPE* lvalp, Context* context) ...@@ -1846,10 +1844,17 @@ int yylex(YYSTYPE* lvalp, Context* context)
switch (token->type) switch (token->type)
{ {
case pp::Token::CONST_INT: case pp::Token::CONST_INT:
*lvalp = strtoll(token->text.c_str(), NULL, 0); {
unsigned int val = 0;
if (!token->uValue(&val))
{
context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW,
token->location, token->text);
}
*lvalp = static_cast<YYSTYPE>(val);
type = CONST_INT; type = CONST_INT;
break; break;
}
case pp::Token::OP_OR: type = OP_OR; break; case pp::Token::OP_OR: type = OP_OR; break;
case pp::Token::OP_AND: type = OP_AND; break; case pp::Token::OP_AND: type = OP_AND; break;
case pp::Token::OP_NE: type = OP_NE; break; case pp::Token::OP_NE: type = OP_NE; break;
......
...@@ -30,7 +30,6 @@ WHICH GENERATES THE GLSL ES preprocessor expression parser. ...@@ -30,7 +30,6 @@ WHICH GENERATES THE GLSL ES preprocessor expression parser.
#include "ExpressionParser.h" #include "ExpressionParser.h"
#include <cassert> #include <cassert>
#include <cstdlib>
#include <sstream> #include <sstream>
#include "Diagnostics.h" #include "Diagnostics.h"
...@@ -39,7 +38,6 @@ WHICH GENERATES THE GLSL ES preprocessor expression parser. ...@@ -39,7 +38,6 @@ WHICH GENERATES THE GLSL ES preprocessor expression parser.
#if defined(_MSC_VER) #if defined(_MSC_VER)
typedef __int64 YYSTYPE; typedef __int64 YYSTYPE;
#define strtoll _strtoi64
#else #else
#include <stdint.h> #include <stdint.h>
typedef intmax_t YYSTYPE; typedef intmax_t YYSTYPE;
...@@ -139,7 +137,7 @@ expression ...@@ -139,7 +137,7 @@ expression
} }
| expression '%' expression { | expression '%' expression {
if ($3 == 0) { if ($3 == 0) {
std::stringstream stream; std::ostringstream stream;
stream << $1 << " % " << $3; stream << $1 << " % " << $3;
std::string text = stream.str(); std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO, context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
...@@ -152,7 +150,7 @@ expression ...@@ -152,7 +150,7 @@ expression
} }
| expression '/' expression { | expression '/' expression {
if ($3 == 0) { if ($3 == 0) {
std::stringstream stream; std::ostringstream stream;
stream << $1 << " / " << $3; stream << $1 << " / " << $3;
std::string text = stream.str(); std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO, context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
...@@ -193,10 +191,17 @@ int yylex(YYSTYPE* lvalp, Context* context) ...@@ -193,10 +191,17 @@ int yylex(YYSTYPE* lvalp, Context* context)
switch (token->type) switch (token->type)
{ {
case pp::Token::CONST_INT: case pp::Token::CONST_INT:
*lvalp = strtoll(token->text.c_str(), NULL, 0); {
unsigned int val = 0;
if (!token->uValue(&val))
{
context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW,
token->location, token->text);
}
*lvalp = static_cast<YYSTYPE>(val);
type = CONST_INT; type = CONST_INT;
break; break;
}
case pp::Token::OP_OR: type = OP_OR; break; case pp::Token::OP_OR: type = OP_OR; break;
case pp::Token::OP_AND: type = OP_AND; break; case pp::Token::OP_AND: type = OP_AND; break;
case pp::Token::OP_NE: type = OP_NE; break; case pp::Token::OP_NE: type = OP_NE; break;
......
...@@ -95,6 +95,48 @@ void Preprocessor::lex(Token* token) ...@@ -95,6 +95,48 @@ void Preprocessor::lex(Token* token)
case Token::PP_HASH: case Token::PP_HASH:
assert(false); assert(false);
break; 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::IDENTIFIER:
{
static const int kMaxIdentifierLength = 256;
if (token->text.size() > kMaxIdentifierLength)
{
// Do not mark the token as invalid.
// Just emit the diagnostic and clamp string length.
mImpl->diagnostics->report(Diagnostics::IDENTIFIER_OVERFLOW,
token->location, token->text);
token->text.erase(kMaxIdentifierLength);
}
validToken = true;
break;
}
case Token::PP_NUMBER: case Token::PP_NUMBER:
mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER, mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER,
token->location, token->text); token->location, token->text);
......
...@@ -6,6 +6,28 @@ ...@@ -6,6 +6,28 @@
#include "Token.h" #include "Token.h"
#include <cassert>
#include <sstream>
template<typename IntType>
static bool atoi_t(const std::string& str, IntType* value)
{
std::ios::fmtflags base = std::ios::dec;
if ((str.size() >= 2) && (str[0] == '0') && (tolower(str[1]) == 'x'))
{
base = std::ios::hex;
}
else if ((str.size() >= 1) && (str[0] == '0'))
{
base = std::ios::oct;
}
std::istringstream stream(str);
stream.setf(base, std::ios::basefield);
stream >> (*value);
return !stream.fail();
}
namespace pp namespace pp
{ {
...@@ -49,6 +71,28 @@ void Token::setExpansionDisabled(bool disable) ...@@ -49,6 +71,28 @@ void Token::setExpansionDisabled(bool disable)
flags &= ~EXPANSION_DISABLED; flags &= ~EXPANSION_DISABLED;
} }
bool Token::iValue(int* value) const
{
assert(type == CONST_INT);
return atoi_t(text, value);
}
bool Token::uValue(unsigned int* value) const
{
assert(type == CONST_INT);
return atoi_t(text, value);
}
bool Token::fValue(float* value) const
{
assert(type == CONST_FLOAT);
std::istringstream stream(text);
stream.imbue(std::locale("C"));
stream >> (*value);
return !stream.fail();
}
std::ostream& operator<<(std::ostream& out, const Token& token) std::ostream& operator<<(std::ostream& out, const Token& token)
{ {
if (token.hasLeadingSpace()) if (token.hasLeadingSpace())
......
...@@ -78,6 +78,12 @@ struct Token ...@@ -78,6 +78,12 @@ struct Token
bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; } bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; }
void setExpansionDisabled(bool disable); void setExpansionDisabled(bool disable);
// Converts text into numeric value for CONST_INT and CONST_FLOAT token.
// Returns false if the parsed value cannot fit into an int or float.
bool iValue(int* value) const;
bool uValue(unsigned int* value) const;
bool fValue(float* value) const;
int type; int type;
unsigned int flags; unsigned int flags;
SourceLocation location; SourceLocation location;
......
...@@ -648,6 +648,48 @@ TEST_F(IfTest, ModuloByZero) ...@@ -648,6 +648,48 @@ TEST_F(IfTest, ModuloByZero)
mPreprocessor.lex(&token); mPreprocessor.lex(&token);
} }
TEST_F(IfTest, DecIntegerOverflow)
{
const char* str = "#if 4294967296\n"
"#endif\n";
ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::INTEGER_OVERFLOW,
pp::SourceLocation(0, 1), "4294967296"));
pp::Token token;
mPreprocessor.lex(&token);
}
TEST_F(IfTest, OctIntegerOverflow)
{
const char* str = "#if 077777777777\n"
"#endif\n";
ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::INTEGER_OVERFLOW,
pp::SourceLocation(0, 1), "077777777777"));
pp::Token token;
mPreprocessor.lex(&token);
}
TEST_F(IfTest, HexIntegerOverflow)
{
const char* str = "#if 0xfffffffff\n"
"#endif\n";
ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::INTEGER_OVERFLOW,
pp::SourceLocation(0, 1), "0xfffffffff"));
pp::Token token;
mPreprocessor.lex(&token);
}
TEST_F(IfTest, UndefinedMacro) TEST_F(IfTest, UndefinedMacro)
{ {
const char* str = "#if UNDEFINED\n" const char* str = "#if UNDEFINED\n"
......
...@@ -295,7 +295,9 @@ static const LineTestParam kParams[] = { ...@@ -295,7 +295,9 @@ static const LineTestParam kParams[] = {
{"#line\n", pp::Diagnostics::INVALID_LINE_DIRECTIVE}, {"#line\n", pp::Diagnostics::INVALID_LINE_DIRECTIVE},
{"#line foo\n", pp::Diagnostics::INVALID_LINE_NUMBER}, {"#line foo\n", pp::Diagnostics::INVALID_LINE_NUMBER},
{"#line 10 foo\n", pp::Diagnostics::INVALID_FILE_NUMBER}, {"#line 10 foo\n", pp::Diagnostics::INVALID_FILE_NUMBER},
{"#line 10 20 foo\n", pp::Diagnostics::UNEXPECTED_TOKEN} {"#line 10 20 foo\n", pp::Diagnostics::UNEXPECTED_TOKEN},
{"#line 0xffffffff\n", pp::Diagnostics::INTEGER_OVERFLOW},
{"#line 10 0xffffffff\n", pp::Diagnostics::INTEGER_OVERFLOW}
}; };
INSTANTIATE_TEST_CASE_P(All, InvalidLineTest, testing::ValuesIn(kParams)); INSTANTIATE_TEST_CASE_P(All, InvalidLineTest, testing::ValuesIn(kParams));
...@@ -90,7 +90,8 @@ TEST_P(InvalidVersionTest, Identified) ...@@ -90,7 +90,8 @@ TEST_P(InvalidVersionTest, Identified)
static const VersionTestParam kParams[] = { static const VersionTestParam kParams[] = {
{"#version\n", pp::Diagnostics::INVALID_VERSION_DIRECTIVE}, {"#version\n", pp::Diagnostics::INVALID_VERSION_DIRECTIVE},
{"#version foo\n", pp::Diagnostics::INVALID_VERSION_NUMBER}, {"#version foo\n", pp::Diagnostics::INVALID_VERSION_NUMBER},
{"#version 100 foo\n", pp::Diagnostics::UNEXPECTED_TOKEN} {"#version 100 foo\n", pp::Diagnostics::UNEXPECTED_TOKEN},
{"#version 0xffffffff\n", pp::Diagnostics::INTEGER_OVERFLOW}
}; };
INSTANTIATE_TEST_CASE_P(All, InvalidVersionTest, testing::ValuesIn(kParams)); INSTANTIATE_TEST_CASE_P(All, InvalidVersionTest, testing::ValuesIn(kParams));
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