Skip to content

Commit 9f445fc

Browse files
committed
Library: simplified code and added test cases for validating <valid>-tag expressions
1 parent 05c36a7 commit 9f445fc

3 files changed

Lines changed: 67 additions & 37 deletions

File tree

lib/library.cpp

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -708,46 +708,11 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
708708
else if (argnodename == "valid") {
709709
// Validate the validation expression
710710
const char *p = argnode->GetText();
711-
bool error = false;
712-
bool range = false;
713-
bool has_dot = false;
714-
bool has_E = false;
715-
716-
if (!p)
717-
return Error(BAD_ATTRIBUTE_VALUE, "\"\"");
718-
719-
error = *p == '.';
720-
for (; *p; p++) {
721-
if (std::isdigit(*p))
722-
error |= (*(p+1) == '-');
723-
else if (*p == ':') {
724-
error |= range | (*(p+1) == '.');
725-
range = true;
726-
has_dot = false;
727-
has_E = false;
728-
} else if (*p == '-')
729-
error |= (!std::isdigit(*(p+1)));
730-
else if (*p == ',') {
731-
range = false;
732-
error |= *(p+1) == '.';
733-
has_dot = false;
734-
has_E = false;
735-
} else if (*p == '.') {
736-
error |= has_dot | (!std::isdigit(*(p+1)));
737-
has_dot = true;
738-
} else if (*p == 'E' || *p == 'e') {
739-
error |= has_E;
740-
has_E = true;
741-
} else
742-
error = true;
743-
}
744-
if (error)
745-
return Error(BAD_ATTRIBUTE_VALUE, argnode->GetText());
746-
711+
if (!isCompliantValidationExpression(p))
712+
return Error(BAD_ATTRIBUTE_VALUE, (!p ? "\"\"" : argnode->GetText()));
747713
// Set validation expression
748714
ac.valid = argnode->GetText();
749715
}
750-
751716
else if (argnodename == "minsize") {
752717
const char *typeattr = argnode->Attribute("type");
753718
if (!typeattr)
@@ -1242,6 +1207,48 @@ const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
12421207
return &i->second;
12431208
}
12441209

1210+
bool Library::isCompliantValidationExpression(const char* p)
1211+
{
1212+
if (!p)
1213+
return false;
1214+
1215+
bool error = false;
1216+
bool range = false;
1217+
bool has_dot = false;
1218+
bool has_E = false;
1219+
1220+
error = *p == '.';
1221+
for (; *p; p++) {
1222+
if (std::isdigit(*p))
1223+
error |= (*(p + 1) == '-');
1224+
else if (*p == ':') {
1225+
error |= range | (*(p + 1) == '.');
1226+
range = true;
1227+
has_dot = false;
1228+
has_E = false;
1229+
}
1230+
else if ((*p == '-')|| (*p == '+'))
1231+
error |= (!std::isdigit(*(p + 1)));
1232+
else if (*p == ',') {
1233+
range = false;
1234+
error |= *(p + 1) == '.';
1235+
has_dot = false;
1236+
has_E = false;
1237+
}
1238+
else if (*p == '.') {
1239+
error |= has_dot | (!std::isdigit(*(p + 1)));
1240+
has_dot = true;
1241+
}
1242+
else if (*p == 'E' || *p == 'e') {
1243+
error |= has_E;
1244+
has_E = true;
1245+
}
1246+
else
1247+
return false;
1248+
}
1249+
return !error;
1250+
}
1251+
12451252
bool Library::formatstr_function(const Token* ftok) const
12461253
{
12471254
if (isNotLibraryFunction(ftok))

lib/library.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ class CPPCHECKLIB Library {
142142
mNoReturn[funcname] = noreturn;
143143
}
144144

145+
static bool isCompliantValidationExpression(const char* p);
146+
145147
/** is allocation type memory? */
146148
static bool ismemory(const int id) {
147149
return ((id > 0) && ((id & 1) == 0));

test/testlibrary.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class TestLibrary : public TestFixture {
4040
Settings settings;
4141

4242
void run() OVERRIDE {
43+
TEST_CASE(isCompliantValidationExpression);
4344
TEST_CASE(empty);
4445
TEST_CASE(function);
4546
TEST_CASE(function_match_scope);
@@ -72,6 +73,26 @@ class TestLibrary : public TestFixture {
7273
return library.load(doc);
7374
}
7475

76+
void isCompliantValidationExpression()
77+
{
78+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("-1"));
79+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1"));
80+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1:"));
81+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":1"));
82+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("-1,42"));
83+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("-1,-42"));
84+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("-1.0:42.0"));
85+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1.175494e-38:3.402823e+38"));
86+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1.175494e-38,3.402823e+38"));
87+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1.175494e-38:"));
88+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":1.175494e-38"));
89+
ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":42.0"));
90+
91+
// Robustness tests
92+
ASSERT_EQUALS(false, Library::isCompliantValidationExpression(nullptr));
93+
ASSERT_EQUALS(false, Library::isCompliantValidationExpression("x"));
94+
}
95+
7596
void empty() const {
7697
// Reading an empty library file is considered to be OK
7798
const char xmldata[] = "<?xml version=\"1.0\"?>\n<def/>";

0 commit comments

Comments
 (0)