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 noMatch = false;
|
||||
const char *needlePointer = needle;
|
||||
for (; *haystack; ++haystack)
|
||||
for (; *haystack && *haystack != ' '; ++haystack)
|
||||
{
|
||||
if (*haystack == '|')
|
||||
{
|
||||
|
@ -260,42 +260,87 @@ bool Token::simpleMatch(const Token *tok, const char pattern[])
|
|||
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)
|
||||
{
|
||||
const char *p = pattern;
|
||||
bool firstpattern = true;
|
||||
bool first = true;
|
||||
while (*p)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
while (*p && *p != ' ')
|
||||
++p;
|
||||
}
|
||||
|
||||
first = false;
|
||||
|
||||
// Skip spaces in pattern..
|
||||
while (*p == ' ')
|
||||
++p;
|
||||
|
||||
// Extract token from pattern..
|
||||
char str[500];
|
||||
char *s = str;
|
||||
while (*p && *p != ' ')
|
||||
{
|
||||
*s = *p;
|
||||
++s;
|
||||
++p;
|
||||
}
|
||||
*s = 0;
|
||||
|
||||
// No token => Success!
|
||||
if (str[0] == 0)
|
||||
if (*p == 0)
|
||||
return true;
|
||||
|
||||
if (!tok)
|
||||
{
|
||||
// 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;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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
|
||||
// before doing more detailed checks.
|
||||
bool patternIdentified = false;
|
||||
if (str[0] == '%')
|
||||
if (p[0] == '%')
|
||||
{
|
||||
// Any symbolname..
|
||||
if (strcmp(str, "%var%") == 0)
|
||||
if (firstWordEquals(p, "%var%") == 0)
|
||||
{
|
||||
if (!tok->isName())
|
||||
return false;
|
||||
|
@ -315,7 +360,7 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
|||
}
|
||||
|
||||
// Type..
|
||||
if (strcmp(str, "%type%") == 0)
|
||||
if (firstWordEquals(p, "%type%") == 0)
|
||||
{
|
||||
if (!tok->isName())
|
||||
return false;
|
||||
|
@ -327,12 +372,12 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
|||
}
|
||||
|
||||
// Accept any token
|
||||
else if (strcmp(str, "%any%") == 0)
|
||||
else if (firstWordEquals(p, "%any%") == 0)
|
||||
{
|
||||
patternIdentified = true;
|
||||
}
|
||||
|
||||
else if (strcmp(str, "%varid%") == 0)
|
||||
else if (firstWordEquals(p, "%varid%") == 0)
|
||||
{
|
||||
if (varid == 0)
|
||||
{
|
||||
|
@ -345,7 +390,7 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
|||
patternIdentified = true;
|
||||
}
|
||||
|
||||
else if (strcmp(str, "%num%") == 0)
|
||||
else if (firstWordEquals(p, "%num%") == 0)
|
||||
{
|
||||
if (!tok->isNumber())
|
||||
return false;
|
||||
|
@ -353,7 +398,7 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
|||
patternIdentified = true;
|
||||
}
|
||||
|
||||
else if (strcmp(str, "%bool%") == 0)
|
||||
else if (firstWordEquals(p, "%bool%") == 0)
|
||||
{
|
||||
if (!tok->isBoolean())
|
||||
return false;
|
||||
|
@ -361,7 +406,7 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
|||
patternIdentified = true;
|
||||
}
|
||||
|
||||
else if (strcmp(str, "%str%") == 0)
|
||||
else if (firstWordEquals(p, "%str%") == 0)
|
||||
{
|
||||
if (tok->_str[0] != '\"')
|
||||
return false;
|
||||
|
@ -376,17 +421,43 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
|
|||
}
|
||||
|
||||
// [.. => 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;
|
||||
if (strchr(str + 1, tok->_str[0]) == 0)
|
||||
const char *temp = p + 1;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// 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
|
||||
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;
|
||||
}
|
||||
|
||||
else if (str != tok->_str)
|
||||
else if (firstWordEquals(p, tok->_str.c_str()) != 0)
|
||||
return false;
|
||||
|
||||
tok = tok->next();
|
||||
|
|
22
src/token.h
22
src/token.h
|
@ -217,6 +217,28 @@ private:
|
|||
void next(Token *next);
|
||||
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;
|
||||
bool _isName;
|
||||
bool _isNumber;
|
||||
|
|
Loading…
Reference in New Issue