Skip to content

Commit 01632ab

Browse files
committed
fixed #14638 - report errors for invalid suppression lines [skip ci]
1 parent d2a0126 commit 01632ab

File tree

3 files changed

+63
-31
lines changed

3 files changed

+63
-31
lines changed

lib/suppressions.cpp

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,8 @@ std::vector<SuppressionList::Suppression> SuppressionList::parseMultiSuppressCom
207207
return suppressions;
208208
}
209209

210-
SuppressionList::Suppression SuppressionList::parseLine(const std::string &line)
210+
SuppressionList::Suppression SuppressionList::parseLine(std::string line)
211211
{
212-
std::istringstream lineStream;
213212
SuppressionList::Suppression suppression;
214213

215214
// Strip any end of line comments
@@ -218,13 +217,18 @@ SuppressionList::Suppression SuppressionList::parseLine(const std::string &line)
218217
while (endpos > 0 && std::isspace(line[endpos-1])) {
219218
endpos--;
220219
}
221-
lineStream.str(line.substr(0, endpos));
222-
} else {
223-
lineStream.str(line);
220+
line = line.substr(0, endpos);
224221
}
225222

226-
if (std::getline(lineStream, suppression.errorId, ':')) {
227-
if (std::getline(lineStream, suppression.fileName)) {
223+
const auto parts = splitString(line, '\n');
224+
const std::string& suppr_l = parts[0];
225+
226+
const std::string::size_type first_sep = suppr_l.find(':');
227+
suppression.errorId = suppr_l.substr(0, first_sep);
228+
if (first_sep != std::string::npos) {
229+
suppression.fileName = suppr_l.substr(first_sep+1);
230+
if (!suppression.fileName.empty()) {
231+
// TODO: this only works with files which have an extension
228232
// If there is not a dot after the last colon in "file" then
229233
// the colon is a separator and the contents after the colon
230234
// is a line number..
@@ -235,38 +239,38 @@ SuppressionList::Suppression SuppressionList::parseLine(const std::string &line)
235239
// if a colon is found and there is no dot after it..
236240
if (pos != std::string::npos &&
237241
suppression.fileName.find('.', pos) == std::string::npos) {
238-
// Try to parse out the line number
239-
try {
240-
std::istringstream istr1(suppression.fileName.substr(pos+1));
241-
istr1 >> suppression.lineNumber;
242-
} catch (...) {
243-
suppression.lineNumber = SuppressionList::Suppression::NO_LINE;
244-
}
245-
246-
if (suppression.lineNumber != SuppressionList::Suppression::NO_LINE) {
247-
suppression.fileName.erase(pos);
248-
}
249-
}
250-
251-
// when parsing string generated internally by toString() there can be newline
252-
std::string extra;
253-
while (std::getline(lineStream, extra)) {
254-
if (startsWith(extra, "symbol="))
255-
suppression.symbolName = extra.substr(7);
256-
else if (extra == "polyspace=1")
257-
suppression.isPolyspace = true;
242+
// parse out the line number
243+
const std::string line_s = suppression.fileName.substr(pos+1);
244+
suppression.lineNumber = strToInt<int>(line_s);
245+
suppression.fileName.erase(pos);
258246
}
247+
suppression.fileName = Path::simplifyPath(suppression.fileName);
248+
} else {
249+
throw std::runtime_error("filename is missing");
259250
}
260251
}
261252

262-
suppression.fileName = Path::simplifyPath(suppression.fileName);
253+
// TODO: make this optional - do we even encounter this in production code?
254+
// when parsing string generated internally by toString() there can be newline
255+
for (std::size_t i = 1; i < parts.size(); ++i) {
256+
if (startsWith(parts[i], "symbol="))
257+
suppression.symbolName = parts[i].substr(7);
258+
else if (parts[i] == "polyspace=1")
259+
suppression.isPolyspace = true;
260+
else
261+
throw std::runtime_error("unexpected extra '" + parts[i] + "'");
262+
}
263263

264264
return suppression;
265265
}
266266

267267
std::string SuppressionList::addSuppressionLine(const std::string &line)
268268
{
269-
return addSuppression(parseLine(line));
269+
try {
270+
return addSuppression(parseLine(line));
271+
} catch (const std::exception& e) {
272+
return e.what();
273+
}
270274
}
271275

272276
std::string SuppressionList::addSuppression(SuppressionList::Suppression suppression)

lib/suppressions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ class CPPCHECKLIB SuppressionList {
197197
* @param line The line to parse.
198198
* @return a suppression object
199199
*/
200-
static Suppression parseLine(const std::string &line);
200+
static Suppression parseLine(std::string line);
201201

202202
/**
203203
* @brief Don't show the given error.

test/testsuppressions.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class TestSuppressions : public TestFixture {
5858
void run() override {
5959
mNewTemplate = true;
6060
TEST_CASE(parseLine);
61+
TEST_CASE(parseLineInvalid);
6162
TEST_CASE(suppressionsBadId1);
6263
TEST_CASE(suppressionsDosFormat); // Ticket #1836
6364
TEST_CASE(suppressionsFileNameWithColon); // Ticket #1919 - filename includes colon
@@ -171,11 +172,38 @@ class TestSuppressions : public TestFixture {
171172
ASSERT_EQUALS("bad:test.c:1\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad:test.c:1\nsymbol=x\npolyspace=1").toString());
172173

173174
// polyspace + symbol
174-
ASSERT_EQUALS("bad\npolyspace=1\nsymbol=x", SuppressionList::parseLine("bad\npolyspace=1\nsymbol=x").toString());
175+
ASSERT_EQUALS("bad\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad\npolyspace=1\nsymbol=x").toString());
175176
ASSERT_EQUALS("bad:test.c\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad:test.c\npolyspace=1\nsymbol=x").toString());
176177
ASSERT_EQUALS("bad:test.c:1\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad:test.c:1\npolyspace=1\nsymbol=x").toString());
177178
}
178179

180+
void parseLineInvalid() const {
181+
// missing filename
182+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:"), std::runtime_error, "filename is missing");
183+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:\n"), std::runtime_error, "filename is missing");
184+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:\n1.c"), std::runtime_error, "filename is missing");
185+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:#1.c"), std::runtime_error, "filename is missing"); // TODO: looks like a valid filename
186+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id://1.c"), std::runtime_error, "filename is missing");
187+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id::"), std::runtime_error, "converting '' to integer failed - not an integer");
188+
189+
// missing/invalid line
190+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:"), std::runtime_error, "converting '' to integer failed - not an integer");
191+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:\n"), std::runtime_error, "converting '' to integer failed - not an integer");
192+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:\n1"), std::runtime_error, "converting '' to integer failed - not an integer");
193+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:#1"), std::runtime_error, "converting '' to integer failed - not an integer"); // TODO: looks like a valid filename
194+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c://1"), std::runtime_error, "converting '' to integer failed - not an integer");
195+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:zero"), std::runtime_error, "converting 'zero' to integer failed - not an integer");
196+
197+
// invalid extras
198+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\n"), std::runtime_error, "unexpected extra ''");
199+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\nsym=x"), std::runtime_error, "unexpected extra 'sym=x'");
200+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\nsymbol:x"), std::runtime_error, "unexpected extra 'symbol:x'");
201+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\npolyspace=0"), std::runtime_error, "unexpected extra 'polyspace=0'");
202+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\npolyspace:1"), std::runtime_error, "unexpected extra 'polyspace:1'");
203+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id\n:"), std::runtime_error, "unexpected extra ':'");
204+
ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c\n:"), std::runtime_error, "unexpected extra ':'");
205+
}
206+
179207
void suppressionsBadId1() const {
180208
SuppressionList suppressions;
181209
std::istringstream s1("123");

0 commit comments

Comments
 (0)