Fix ticket #306 (Invalid multi-line comment produces cryptic internal error)
http://apps.sourceforge.net/trac/cppcheck/ticket/306
This commit is contained in:
parent
997a784bb6
commit
e5e82274dc
|
@ -71,9 +71,6 @@ std::string Preprocessor::read(std::istream &istr)
|
||||||
std::ostringstream code;
|
std::ostringstream code;
|
||||||
for (char ch = readChar(istr); istr.good(); ch = readChar(istr))
|
for (char ch = readChar(istr); istr.good(); ch = readChar(istr))
|
||||||
{
|
{
|
||||||
if (ch < 0)
|
|
||||||
throw std::runtime_error("The code contains characters that are unhandled");
|
|
||||||
|
|
||||||
if (ch == '\n')
|
if (ch == '\n')
|
||||||
++lineno;
|
++lineno;
|
||||||
|
|
||||||
|
@ -84,7 +81,7 @@ std::string Preprocessor::read(std::istream &istr)
|
||||||
// Skip spaces after ' ' and after '#'
|
// Skip spaces after ' ' and after '#'
|
||||||
if (ch == ' ' && ignoreSpace)
|
if (ch == ' ' && ignoreSpace)
|
||||||
continue;
|
continue;
|
||||||
ignoreSpace = bool(ch == ' ' || ch == '#' || ch == '/');
|
ignoreSpace = bool(ch == ' ' || ch == '#' || ch == '/' || ch == '\n');
|
||||||
|
|
||||||
if (needSpace)
|
if (needSpace)
|
||||||
{
|
{
|
||||||
|
@ -96,68 +93,8 @@ std::string Preprocessor::read(std::istream &istr)
|
||||||
if (ch == '#')
|
if (ch == '#')
|
||||||
needSpace = true;
|
needSpace = true;
|
||||||
|
|
||||||
// Remove comments..
|
|
||||||
if (ch == '/')
|
|
||||||
{
|
|
||||||
char chNext = readChar(istr);
|
|
||||||
|
|
||||||
if (chNext == '/')
|
|
||||||
{
|
|
||||||
while (istr.good() && ch != '\n')
|
|
||||||
ch = readChar(istr);
|
|
||||||
code << "\n";
|
|
||||||
++lineno;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (chNext == '*')
|
|
||||||
{
|
|
||||||
char chPrev = 0;
|
|
||||||
while (istr.good() && (chPrev != '*' || ch != '/'))
|
|
||||||
{
|
|
||||||
chPrev = ch;
|
|
||||||
ch = readChar(istr);
|
|
||||||
if (ch == '\n')
|
|
||||||
{
|
|
||||||
code << "\n";
|
|
||||||
++lineno;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (chNext == '\n')
|
|
||||||
++lineno;
|
|
||||||
code << std::string(1, ch) << std::string(1, chNext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String or char constants..
|
|
||||||
else if (ch == '\"' || ch == '\'')
|
|
||||||
{
|
|
||||||
code << std::string(1, ch);
|
|
||||||
char chNext;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
chNext = (char)istr.get();
|
|
||||||
if (chNext == '\\')
|
|
||||||
{
|
|
||||||
char chSeq = readChar(istr);
|
|
||||||
if (chSeq == '\n')
|
|
||||||
++newlines;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
code << std::string(1, chNext);
|
|
||||||
code << std::string(1, chSeq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
code << std::string(1, chNext);
|
|
||||||
}
|
|
||||||
while (istr.good() && chNext != ch);
|
|
||||||
}
|
|
||||||
// <backspace><newline>..
|
// <backspace><newline>..
|
||||||
else if (ch == '\\')
|
if (ch == '\\')
|
||||||
{
|
{
|
||||||
char chNext = 0;
|
char chNext = 0;
|
||||||
while (true)
|
while (true)
|
||||||
|
@ -197,6 +134,111 @@ std::string Preprocessor::read(std::istream &istr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return removeComments(code.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::string Preprocessor::removeComments(const std::string &str)
|
||||||
|
{
|
||||||
|
// For the error report
|
||||||
|
int lineno = 1;
|
||||||
|
|
||||||
|
// handling <backspace><newline>
|
||||||
|
// when this is encountered the <backspace><newline> will be "skipped".
|
||||||
|
// on the next <newline>, extra newlines will be added
|
||||||
|
unsigned int newlines = 0;
|
||||||
|
|
||||||
|
std::ostringstream code;
|
||||||
|
for (std::string::size_type i = 0; i < str.length(); ++i)
|
||||||
|
{
|
||||||
|
char ch = str[i];
|
||||||
|
if (ch < 0)
|
||||||
|
throw std::runtime_error("The code contains characters that are unhandled");
|
||||||
|
|
||||||
|
// Remove comments..
|
||||||
|
if (ch == '/')
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
char chNext = str[i];
|
||||||
|
|
||||||
|
if (chNext == '/')
|
||||||
|
{
|
||||||
|
while (i < str.length() && ch != '\n')
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
ch = str[i];
|
||||||
|
}
|
||||||
|
code << "\n";
|
||||||
|
++lineno;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (chNext == '*')
|
||||||
|
{
|
||||||
|
char chPrev = 0;
|
||||||
|
while (i < str.length() && (chPrev != '*' || ch != '/'))
|
||||||
|
{
|
||||||
|
chPrev = ch;
|
||||||
|
++i;
|
||||||
|
ch = str[i];
|
||||||
|
if (ch == '\n')
|
||||||
|
{
|
||||||
|
code << "\n";
|
||||||
|
++lineno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (chNext == '\n')
|
||||||
|
++lineno;
|
||||||
|
code << std::string(1, ch) << std::string(1, chNext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String or char constants..
|
||||||
|
else if (ch == '\"' || ch == '\'')
|
||||||
|
{
|
||||||
|
code << std::string(1, ch);
|
||||||
|
char chNext;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
chNext = str[i];
|
||||||
|
if (chNext == '\\')
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
char chSeq = str[i];
|
||||||
|
if (chSeq == '\n')
|
||||||
|
++newlines;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
code << std::string(1, chNext);
|
||||||
|
code << std::string(1, chSeq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
code << std::string(1, chNext);
|
||||||
|
}
|
||||||
|
while (i < str.length() && chNext != ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Just some code..
|
||||||
|
else
|
||||||
|
{
|
||||||
|
code << std::string(1, ch);
|
||||||
|
|
||||||
|
// if there has been <backspace><newline> sequences, add extra newlines..
|
||||||
|
if (ch == '\n' && newlines > 0)
|
||||||
|
{
|
||||||
|
code << std::string(newlines, '\n');
|
||||||
|
newlines = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return code.str();
|
return code.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,13 @@ protected:
|
||||||
|
|
||||||
static std::string expandMacros(std::string code, const std::string &filename, ErrorLogger *errorLogger);
|
static std::string expandMacros(std::string code, const std::string &filename, ErrorLogger *errorLogger);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove comments from code. This should only be called from read().
|
||||||
|
* @param str Code processed by read().
|
||||||
|
* @return code without comments
|
||||||
|
*/
|
||||||
|
static std::string removeComments(const std::string &str);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -234,7 +234,7 @@ private:
|
||||||
preprocessor.preprocess(istr, actual, "file.c");
|
preprocessor.preprocess(istr, actual, "file.c");
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
ASSERT_EQUALS("\n\" # ifdef WIN32\"\n\n\n\n", actual[""]);
|
ASSERT_EQUALS("\n\" #ifdef WIN32\"\n\n\n\n", actual[""]);
|
||||||
ASSERT_EQUALS("\n\n\nqwerty\n\n", actual["WIN32"]);
|
ASSERT_EQUALS("\n\n\nqwerty\n\n", actual["WIN32"]);
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
||||||
}
|
}
|
||||||
|
@ -383,20 +383,39 @@ private:
|
||||||
|
|
||||||
void comments1()
|
void comments1()
|
||||||
{
|
{
|
||||||
const char filedata[] = "/*\n"
|
{
|
||||||
"#ifdef WIN32\n"
|
const char filedata[] = "/*\n"
|
||||||
"#endif\n"
|
"#ifdef WIN32\n"
|
||||||
"*/\n";
|
"#endif\n"
|
||||||
|
"*/\n";
|
||||||
|
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor;
|
Preprocessor preprocessor;
|
||||||
preprocessor.preprocess(istr, actual, "file.c");
|
preprocessor.preprocess(istr, actual, "file.c");
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
ASSERT_EQUALS("\n\n\n\n", actual[""]);
|
ASSERT_EQUALS("\n\n\n\n", actual[""]);
|
||||||
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char filedata[] = "/*\n"
|
||||||
|
"\x080 #ifdef WIN32\n"
|
||||||
|
"#endif\n"
|
||||||
|
"*/\n";
|
||||||
|
|
||||||
|
// Preprocess => actual result..
|
||||||
|
std::istringstream istr(filedata);
|
||||||
|
std::map<std::string, std::string> actual;
|
||||||
|
Preprocessor preprocessor;
|
||||||
|
preprocessor.preprocess(istr, actual, "file.c");
|
||||||
|
|
||||||
|
// Compare results..
|
||||||
|
ASSERT_EQUALS("\n\n\n\n", actual[""]);
|
||||||
|
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -944,7 +963,7 @@ private:
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
ASSERT_EQUALS(1, static_cast<unsigned int>(actual.size()));
|
||||||
TODO_ASSERT_EQUALS("\n\nvoid f() { }\n", actual[""]);
|
ASSERT_EQUALS("\n\nvoid f() { }\n", actual[""]);
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue