Skip to content

Commit c4635cf

Browse files
committed
Improved check: portability message when calling memset on a class with floating point numbers (danmar#5421)
1 parent a1b7ab2 commit c4635cf

3 files changed

Lines changed: 60 additions & 5 deletions

File tree

lib/checkclass.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,7 +1037,7 @@ void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Sco
10371037
std::list<Variable>::const_iterator var;
10381038

10391039
for (var = type->varlist.begin(); var != type->varlist.end(); ++var) {
1040-
if (var->isReference()) {
1040+
if (var->isReference() && !var->isStatic()) {
10411041
memsetErrorReference(tok, tok->str(), type->classDef->str());
10421042
continue;
10431043
}
@@ -1056,6 +1056,10 @@ void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Sco
10561056
// check for known type
10571057
else if (typeScope && typeScope != type)
10581058
checkMemsetType(start, tok, typeScope, allocation, parsedTypes);
1059+
1060+
// check for float
1061+
else if ((var->typeStartToken()->str() == "float" || var->typeStartToken()->str() == "double") && _settings->isEnabled("portability"))
1062+
memsetErrorFloat(tok, tok->str(), type->classDef->str());
10591063
}
10601064
}
10611065
}
@@ -1093,7 +1097,14 @@ void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const
10931097

10941098
void CheckClass::memsetErrorReference(const Token *tok, const std::string &memfunc, const std::string &type)
10951099
{
1096-
reportError(tok, Severity::error, "memsetClass", "Using '" + memfunc + "' on " + type + " that contains a reference.");
1100+
reportError(tok, Severity::error, "memsetClassReference", "Using '" + memfunc + "' on " + type + " that contains a reference.");
1101+
}
1102+
1103+
void CheckClass::memsetErrorFloat(const Token *tok, const std::string &memfunc, const std::string &type)
1104+
{
1105+
reportError(tok, Severity::portability, "memsetClassFloat", "Using '" + memfunc + "' on " + type + " which contains a floating point number.\n"
1106+
"Using '" + memfunc + "' on " + type + " which contains a floating point number. This is not portable because memset() sets each byte of a block of memory to a specific value and"
1107+
" the actual representation of a floating-point value is implementation defined.");
10971108
}
10981109

10991110

lib/checkclass.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ class CPPCHECKLIB CheckClass : public Check {
144144
void unusedPrivateFunctionError(const Token *tok, const std::string &classname, const std::string &funcname);
145145
void memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type);
146146
void memsetErrorReference(const Token *tok, const std::string &memfunc, const std::string &type);
147+
void memsetErrorFloat(const Token *tok, const std::string &memfunc, const std::string &type);
147148
void mallocOnClassError(const Token* tok, const std::string &memfunc, const Token* classTok, const std::string &classname);
148149
void mallocOnClassWarning(const Token* tok, const std::string &memfunc, const Token* classTok);
149150
void operatorEqReturnError(const Token *tok, const std::string &className);
@@ -169,6 +170,8 @@ class CPPCHECKLIB CheckClass : public Check {
169170
c.operatorEqVarError(0, "classname", "", false);
170171
c.unusedPrivateFunctionError(0, "classname", "funcname");
171172
c.memsetError(0, "memfunc", "classname", "class");
173+
c.memsetErrorReference(0, "memfunc", "class");
174+
c.memsetErrorFloat(0, "memfunc", "class");
172175
c.mallocOnClassWarning(0, "malloc", 0);
173176
c.mallocOnClassError(0, "malloc", 0, "std::string");
174177
c.operatorEqReturnError(0, "class");

test/testclass.cpp

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ class TestClass : public TestFixture {
7373
TEST_CASE(memsetOnStruct);
7474
TEST_CASE(memsetVector);
7575
TEST_CASE(memsetOnClass);
76-
TEST_CASE(memsetOnInvalid); // Ticket #5425: Crash upon invalid
77-
TEST_CASE(memsetOnStdPodType); // #5901 - std::uint8_t
76+
TEST_CASE(memsetOnInvalid); // Ticket #5425: Crash upon invalid
77+
TEST_CASE(memsetOnStdPodType); // Ticket #5901 - std::uint8_t
78+
TEST_CASE(memsetOnFloat); // Ticket #5421
7879
TEST_CASE(mallocOnClass);
7980

8081
TEST_CASE(this_subtraction); // warn about "this-x"
@@ -2007,12 +2008,14 @@ class TestClass : public TestFixture {
20072008
ASSERT_EQUALS("[test.cpp:3]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor.\n", errout.str());
20082009
}
20092010

2010-
void checkNoMemset(const char code[], bool load_std_cfg = false) {
2011+
void checkNoMemset(const char code[], bool load_std_cfg = false, bool portability = false) {
20112012
// Clear the error log
20122013
errout.str("");
20132014

20142015
Settings settings;
20152016
settings.addEnabled("warning");
2017+
if (portability)
2018+
settings.addEnabled("portability");
20162019
if (load_std_cfg) {
20172020
LOAD_LIB_2(settings.library, "std.cfg");
20182021
}
@@ -2470,6 +2473,44 @@ class TestClass : public TestFixture {
24702473
ASSERT_EQUALS("", errout.str());
24712474
}
24722475

2476+
void memsetOnFloat() {
2477+
checkNoMemset("struct A {\n"
2478+
" float f;\n"
2479+
"};\n"
2480+
"void f() {\n"
2481+
" A a;\n"
2482+
" memset(&a, 0, sizeof(A));\n"
2483+
"}", false, true);
2484+
ASSERT_EQUALS("[test.cpp:6]: (portability) Using 'memset' on struct which contains a floating point number.\n", errout.str());
2485+
2486+
checkNoMemset("struct A {\n"
2487+
" float f[4];\n"
2488+
"};\n"
2489+
"void f() {\n"
2490+
" A a;\n"
2491+
" memset(&a, 0, sizeof(A));\n"
2492+
"}", false, true);
2493+
ASSERT_EQUALS("[test.cpp:6]: (portability) Using 'memset' on struct which contains a floating point number.\n", errout.str());
2494+
2495+
checkNoMemset("struct A {\n"
2496+
" float* f;\n"
2497+
"};\n"
2498+
"void f() {\n"
2499+
" A a;\n"
2500+
" memset(&a, 0, sizeof(A));\n"
2501+
"}", false, true);
2502+
ASSERT_EQUALS("", errout.str());
2503+
2504+
checkNoMemset("struct A {\n"
2505+
" float f;\n"
2506+
"};\n"
2507+
"void f() {\n"
2508+
" A a;\n"
2509+
" memset(&a, 0, sizeof(A));\n"
2510+
"}", false, false);
2511+
ASSERT_EQUALS("", errout.str());
2512+
}
2513+
24732514
void mallocOnClass() {
24742515
checkNoMemset("class C { C() {} };\n"
24752516
"void foo(C*& p) {\n"

0 commit comments

Comments
 (0)