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)
return "invalid character";
case 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:
return "invalid expression";
case DIVISION_BY_ZERO:
......
......@@ -31,6 +31,9 @@ class Diagnostics
OUT_OF_MEMORY,
INVALID_CHARACTER,
INVALID_NUMBER,
INTEGER_OVERFLOW,
FLOAT_OVERFLOW,
IDENTIFIER_OVERFLOW,
INVALID_EXPRESSION,
DIVISION_BY_ZERO,
EOF_IN_COMMENT,
......
......@@ -550,7 +550,7 @@ void DirectiveParser::parseError(Token* token)
{
assert(getDirective(token) == DIRECTIVE_ERROR);
std::stringstream stream;
std::ostringstream stream;
mTokenizer->lex(token);
while ((token->type != '\n') && (token->type != Token::LAST))
{
......@@ -709,7 +709,12 @@ void DirectiveParser::parseVersion(Token* token)
token->location, token->text);
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;
default:
if (valid)
......@@ -759,7 +764,12 @@ void DirectiveParser::parseLine(Token* token)
token->location, token->text);
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;
case FILE_NUMBER:
if (valid && (token->type != Token::CONST_INT))
......@@ -768,7 +778,12 @@ void DirectiveParser::parseLine(Token* token)
token->location, token->text);
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;
default:
if (valid)
......
......@@ -93,7 +93,6 @@
#include "ExpressionParser.h"
#include <cassert>
#include <cstdlib>
#include <sstream>
#include "Diagnostics.h"
......@@ -102,7 +101,6 @@
#if defined(_MSC_VER)
typedef __int64 YYSTYPE;
#define strtoll _strtoi64
#else
#include <stdint.h>
typedef intmax_t YYSTYPE;
......@@ -469,9 +467,9 @@ static const yytype_int8 yyrhs[] =
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint8 yyrline[] =
{
0, 87, 87, 94, 95, 98, 101, 104, 107, 110,
113, 116, 119, 122, 125, 128, 131, 134, 137, 140,
153, 166, 169, 172, 175, 178, 181
0, 85, 85, 92, 93, 96, 99, 102, 105, 108,
111, 114, 117, 120, 123, 126, 129, 132, 135, 138,
151, 164, 167, 170, 173, 176, 179
};
#endif
......@@ -1552,7 +1550,7 @@ yyreduce:
{
if ((yyvsp[(3) - (3)]) == 0) {
std::stringstream stream;
std::ostringstream stream;
stream << (yyvsp[(1) - (3)]) << " % " << (yyvsp[(3) - (3)]);
std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
......@@ -1569,7 +1567,7 @@ yyreduce:
{
if ((yyvsp[(3) - (3)]) == 0) {
std::stringstream stream;
std::ostringstream stream;
stream << (yyvsp[(1) - (3)]) << " / " << (yyvsp[(3) - (3)]);
std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
......@@ -1846,10 +1844,17 @@ int yylex(YYSTYPE* lvalp, Context* context)
switch (token->type)
{
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;
break;
}
case pp::Token::OP_OR: type = OP_OR; break;
case pp::Token::OP_AND: type = OP_AND; break;
case pp::Token::OP_NE: type = OP_NE; break;
......
......@@ -30,7 +30,6 @@ WHICH GENERATES THE GLSL ES preprocessor expression parser.
#include "ExpressionParser.h"
#include <cassert>
#include <cstdlib>
#include <sstream>
#include "Diagnostics.h"
......@@ -39,7 +38,6 @@ WHICH GENERATES THE GLSL ES preprocessor expression parser.
#if defined(_MSC_VER)
typedef __int64 YYSTYPE;
#define strtoll _strtoi64
#else
#include <stdint.h>
typedef intmax_t YYSTYPE;
......@@ -139,7 +137,7 @@ expression
}
| expression '%' expression {
if ($3 == 0) {
std::stringstream stream;
std::ostringstream stream;
stream << $1 << " % " << $3;
std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
......@@ -152,7 +150,7 @@ expression
}
| expression '/' expression {
if ($3 == 0) {
std::stringstream stream;
std::ostringstream stream;
stream << $1 << " / " << $3;
std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
......@@ -193,10 +191,17 @@ int yylex(YYSTYPE* lvalp, Context* context)
switch (token->type)
{
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;
break;
}
case pp::Token::OP_OR: type = OP_OR; break;
case pp::Token::OP_AND: type = OP_AND; break;
case pp::Token::OP_NE: type = OP_NE; break;
......
......@@ -95,6 +95,48 @@ void Preprocessor::lex(Token* token)
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::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:
mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER,
token->location, token->text);
......
......@@ -6,6 +6,28 @@
#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
{
......@@ -49,6 +71,28 @@ void Token::setExpansionDisabled(bool disable)
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)
{
if (token.hasLeadingSpace())
......
......@@ -78,6 +78,12 @@ struct Token
bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; }
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;
unsigned int flags;
SourceLocation location;
......
......@@ -648,6 +648,48 @@ TEST_F(IfTest, ModuloByZero)
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)
{
const char* str = "#if UNDEFINED\n"
......
......@@ -295,7 +295,9 @@ static const LineTestParam kParams[] = {
{"#line\n", pp::Diagnostics::INVALID_LINE_DIRECTIVE},
{"#line foo\n", pp::Diagnostics::INVALID_LINE_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));
......@@ -90,7 +90,8 @@ TEST_P(InvalidVersionTest, Identified)
static const VersionTestParam kParams[] = {
{"#version\n", pp::Diagnostics::INVALID_VERSION_DIRECTIVE},
{"#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));
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