Fix ticket #543 (Possible buffer overrun in Token::Match())
http://sourceforge.net/apps/trac/cppcheck/ticket/543 Get rid of string copying in Token::Match(), also improves speed a little. 8.0s -> 7.7s
This commit is contained in:
parent
232f62f98a
commit
36a8e8afba
133
src/token.cpp
133
src/token.cpp
|
@ -169,7 +169,7 @@ int Token::multiCompare(const char *haystack, const char *needle)
|
||||||
bool emptyStringFound = false;
|
bool emptyStringFound = false;
|
||||||
bool noMatch = false;
|
bool noMatch = false;
|
||||||
const char *needlePointer = needle;
|
const char *needlePointer = needle;
|
||||||
for (; *haystack; ++haystack)
|
for (; *haystack && *haystack != ' '; ++haystack)
|
||||||
{
|
{
|
||||||
if (*haystack == '|')
|
if (*haystack == '|')
|
||||||
{
|
{
|
||||||
|
@ -260,42 +260,87 @@ bool Token::simpleMatch(const Token *tok, const char pattern[])
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Token::firstWordEquals(const char *str, const char *word)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (*str == ' ' && *word == 0)
|
||||||
|
return 0;
|
||||||
|
else if (*str != *word)
|
||||||
|
return 1;
|
||||||
|
else if (*str == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
++str;
|
||||||
|
++word;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Token::chrInFirstWord(const char *str, char c)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (*str == ' ' || *str == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (*str == c)
|
||||||
|
return str;
|
||||||
|
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Token::firstWordLen(const char *str)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (*str == ' ' || *str == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
++len;
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
||||||
{
|
{
|
||||||
const char *p = pattern;
|
const char *p = pattern;
|
||||||
bool firstpattern = true;
|
bool firstpattern = true;
|
||||||
|
bool first = true;
|
||||||
while (*p)
|
while (*p)
|
||||||
{
|
{
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
while (*p && *p != ' ')
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
|
||||||
// Skip spaces in pattern..
|
// Skip spaces in pattern..
|
||||||
while (*p == ' ')
|
while (*p == ' ')
|
||||||
++p;
|
++p;
|
||||||
|
|
||||||
// Extract token from pattern..
|
|
||||||
char str[500];
|
|
||||||
char *s = str;
|
|
||||||
while (*p && *p != ' ')
|
|
||||||
{
|
|
||||||
*s = *p;
|
|
||||||
++s;
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
*s = 0;
|
|
||||||
|
|
||||||
// No token => Success!
|
// No token => Success!
|
||||||
if (str[0] == 0)
|
if (*p == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!tok)
|
if (!tok)
|
||||||
{
|
{
|
||||||
// If we have no tokens, pattern "!!else" should return true
|
// If we have no tokens, pattern "!!else" should return true
|
||||||
if (str[1] == '!' && str[0] == '!' && str[2] != '\0')
|
if (p[1] == '!' && p[0] == '!' && p[2] != '\0')
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are in the first token, we skip all initial !! patterns
|
// If we are in the first token, we skip all initial !! patterns
|
||||||
if (firstpattern && !tok->previous() && tok->next() && str[1] == '!' && str[0] == '!' && str[2] != '\0')
|
if (firstpattern && !tok->previous() && tok->next() && p[1] == '!' && p[0] == '!' && p[2] != '\0')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
firstpattern = false;
|
firstpattern = false;
|
||||||
|
@ -303,10 +348,10 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
||||||
// Compare the first character of the string for optimization reasons
|
// Compare the first character of the string for optimization reasons
|
||||||
// before doing more detailed checks.
|
// before doing more detailed checks.
|
||||||
bool patternIdentified = false;
|
bool patternIdentified = false;
|
||||||
if (str[0] == '%')
|
if (p[0] == '%')
|
||||||
{
|
{
|
||||||
// Any symbolname..
|
// Any symbolname..
|
||||||
if (strcmp(str, "%var%") == 0)
|
if (firstWordEquals(p, "%var%") == 0)
|
||||||
{
|
{
|
||||||
if (!tok->isName())
|
if (!tok->isName())
|
||||||
return false;
|
return false;
|
||||||
|
@ -315,7 +360,7 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type..
|
// Type..
|
||||||
if (strcmp(str, "%type%") == 0)
|
if (firstWordEquals(p, "%type%") == 0)
|
||||||
{
|
{
|
||||||
if (!tok->isName())
|
if (!tok->isName())
|
||||||
return false;
|
return false;
|
||||||
|
@ -327,12 +372,12 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept any token
|
// Accept any token
|
||||||
else if (strcmp(str, "%any%") == 0)
|
else if (firstWordEquals(p, "%any%") == 0)
|
||||||
{
|
{
|
||||||
patternIdentified = true;
|
patternIdentified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp(str, "%varid%") == 0)
|
else if (firstWordEquals(p, "%varid%") == 0)
|
||||||
{
|
{
|
||||||
if (varid == 0)
|
if (varid == 0)
|
||||||
{
|
{
|
||||||
|
@ -345,7 +390,7 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
||||||
patternIdentified = true;
|
patternIdentified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp(str, "%num%") == 0)
|
else if (firstWordEquals(p, "%num%") == 0)
|
||||||
{
|
{
|
||||||
if (!tok->isNumber())
|
if (!tok->isNumber())
|
||||||
return false;
|
return false;
|
||||||
|
@ -353,7 +398,7 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
||||||
patternIdentified = true;
|
patternIdentified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp(str, "%bool%") == 0)
|
else if (firstWordEquals(p, "%bool%") == 0)
|
||||||
{
|
{
|
||||||
if (!tok->isBoolean())
|
if (!tok->isBoolean())
|
||||||
return false;
|
return false;
|
||||||
|
@ -361,7 +406,7 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
||||||
patternIdentified = true;
|
patternIdentified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp(str, "%str%") == 0)
|
else if (firstWordEquals(p, "%str%") == 0)
|
||||||
{
|
{
|
||||||
if (tok->_str[0] != '\"')
|
if (tok->_str[0] != '\"')
|
||||||
return false;
|
return false;
|
||||||
|
@ -376,17 +421,43 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// [.. => search for a one-character token..
|
// [.. => search for a one-character token..
|
||||||
else if (str[0] == '[' && strchr(str, ']') && tok->_str[1] == 0)
|
else if (p[0] == '[' && chrInFirstWord(p, ']') && tok->_str[1] == 0)
|
||||||
{
|
{
|
||||||
*strrchr(str, ']') = 0;
|
const char *temp = p + 1;
|
||||||
if (strchr(str + 1, tok->_str[0]) == 0)
|
bool chrFound = false;
|
||||||
|
int count = 0;
|
||||||
|
while (*temp && *temp != ' ')
|
||||||
|
{
|
||||||
|
if (*temp == ']')
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
++temp;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*temp == tok->_str[0])
|
||||||
|
{
|
||||||
|
chrFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
if (tok->_str[0] == ']')
|
||||||
|
chrFound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chrFound)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse multi options, such as void|int|char (accept token which is one of these 3)
|
// Parse multi options, such as void|int|char (accept token which is one of these 3)
|
||||||
else if (strchr(str, '|') && (str[0] != '|' || strlen(str) > 2))
|
else if (chrInFirstWord(p, '|') && (p[0] != '|' || firstWordLen(p) > 2))
|
||||||
{
|
{
|
||||||
int res = multiCompare(str, tok->_str.c_str());
|
int res = multiCompare(p, tok->_str.c_str());
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
{
|
{
|
||||||
// Empty alternative matches, use the same token on next round
|
// Empty alternative matches, use the same token on next round
|
||||||
|
@ -400,13 +471,13 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse "not" options. Token can be anything except the given one
|
// Parse "not" options. Token can be anything except the given one
|
||||||
else if (str[1] == '!' && str[0] == '!' && str[2] != '\0')
|
else if (p[1] == '!' && p[0] == '!' && p[2] != '\0')
|
||||||
{
|
{
|
||||||
if (strcmp(tok->str().c_str(), &(str[2])) == 0)
|
if (firstWordEquals(&(p[2]), tok->str().c_str()) == 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (str != tok->_str)
|
else if (firstWordEquals(p, tok->_str.c_str()) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
|
|
22
src/token.h
22
src/token.h
|
@ -217,6 +217,28 @@ private:
|
||||||
void next(Token *next);
|
void next(Token *next);
|
||||||
void previous(Token *previous);
|
void previous(Token *previous);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Works almost like strcmp() except returns only 0 or 1 and
|
||||||
|
* if str has empty space ' ' character, that character is handled
|
||||||
|
* as if it were '\0'
|
||||||
|
*/
|
||||||
|
static int firstWordEquals(const char *str, const char *word);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Works almost like strchr() except
|
||||||
|
* if str has empty space ' ' character, that character is handled
|
||||||
|
* as if it were '\0'
|
||||||
|
*/
|
||||||
|
static const char *chrInFirstWord(const char *str, char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Works almost like strlen() except
|
||||||
|
* if str has empty space ' ' character, that character is handled
|
||||||
|
* as if it were '\0'
|
||||||
|
*/
|
||||||
|
static int firstWordLen(const char *str);
|
||||||
|
|
||||||
|
|
||||||
std::string _str;
|
std::string _str;
|
||||||
bool _isName;
|
bool _isName;
|
||||||
bool _isNumber;
|
bool _isNumber;
|
||||||
|
|
Loading…
Reference in New Issue