From 3de152d52313b19e3436f53579cfbb0682f8cca2 Mon Sep 17 00:00:00 2001 From: olabetskyi <153490942+olabetskyi@users.noreply.github.com> Date: Tue, 13 Feb 2024 17:44:44 +0200 Subject: [PATCH 01/15] #12247: dump file: Add "hasOverrideSpecifier" and "hasFinalSpecifier" to Function (#5981) --- lib/symboldatabase.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 32b9c921e73..6cd1d519454 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -4281,6 +4281,10 @@ void SymbolDatabase::printXml(std::ostream &out) const outs += accessControlToString(function->access); outs +="\""; } + if (function->hasOverrideSpecifier()) + outs += " hasOverrideSpecifier=\"true\""; + if (function->hasFinalSpecifier()) + outs += " hasFinalSpecifier=\"true\""; if (function->isInlineKeyword()) outs += " isInlineKeyword=\"true\""; if (function->isStatic()) From 2a2741244962efc1a0d54fabe70796c4d15e1d5e Mon Sep 17 00:00:00 2001 From: wienans <40465543+wienans@users.noreply.github.com> Date: Wed, 14 Feb 2024 13:58:54 +0100 Subject: [PATCH 02/15] Add Original Name to types for Typedefs (#5968) Trying to Fix the issue described here: https://sourceforge.net/p/cppcheck/discussion/general/thread/5775ff1666/ For the small example purpose script it works. Actually it shows the `valueType-originalTypeName`. But i am not 100% sure, what is done. I printed the tok2 and tok3 and in my simple case both where the same. And if i add either of both the originalName it also works. But for now i couldn't deduct what exactly tok2 and tok3 are doing --- lib/tokenize.cpp | 2 ++ test/testsimplifytypedef.cpp | 58 ++++++++++++++++++++++++++++++++++++ test/testsymboldatabase.cpp | 47 +++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9002f514813..eaf999979fd 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -828,6 +828,8 @@ namespace { Token* const tok2 = insertTokens(tok, rangeType); Token* const tok3 = insertTokens(tok2, mRangeTypeQualifiers); + tok2->originalName(tok->str()); + tok3->originalName(tok->str()); Token *after = tok3; while (Token::Match(after, "%name%|*|&|&&|::")) after = after->next(); diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index b3096edffcb..a63538f346b 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -230,6 +230,8 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedefShadow); // #4445 - shadow variable TEST_CASE(simplifyTypedefMacro); + + TEST_CASE(simplifyTypedefOriginalName); } #define tok(...) tok_(__FILE__, __LINE__, __VA_ARGS__) @@ -4131,6 +4133,62 @@ class TestSimplifyTypedef : public TestFixture { ASSERT_EQUALS("void foo ( uint32_t prev_segment ) { if ( prev_segment == ( ( uint32_t ) 12 ) ) { } }", simplifyTypedefP(code)); } + + void simplifyTypedefOriginalName() { + const char code[] = "typedef unsigned char uint8_t;" + "typedef float (*rFunctionPointer_fp)(uint8_t, uint8_t);" + "typedef enum eEnumDef {" + " ABC = 0," + "}eEnum_t;" + "typedef enum {" + " ABC = 0," + "}eEnum2_t;" + "typedef short int16_t;" + "typedef struct stStructDef {" + " int16_t swA;" + "}stStruct_t;" + "double endOfTypeDef;" + "eEnum2_t enum2Type;" + "stStruct_t structType;" + "eEnum_t enumType;" + "uint8_t t;" + "void test(rFunctionPointer_fp functionPointer);"; + + Tokenizer tokenizer(settings1, this); + std::istringstream istr(code); + tokenizer.list.createTokens(istr, "file.c"); + tokenizer.createLinks(); + tokenizer.simplifyTypedef(); + + try { + tokenizer.validate(); + } + catch (const InternalError&) { + ASSERT_EQUALS_MSG(false, true, "Validation of Tokenizer failed"); + } + + const Token* token; + // Get the Token which is at the end of all the Typedef's in this case i placed a variable + const Token* endOfTypeDef = Token::findsimplematch(tokenizer.list.front(), "endOfTypeDef", tokenizer.list.back()); + // Search for the simplified char token and check its original Name + token = Token::findsimplematch(endOfTypeDef, "char", tokenizer.list.back()); + ASSERT_EQUALS("uint8_t", token->originalName()); + // Search for the simplified eEnumDef token and check its original Name + token = Token::findsimplematch(endOfTypeDef, "eEnumDef", tokenizer.list.back()); + ASSERT_EQUALS("eEnum_t", token->originalName()); + // Search for the eEnum2_t token as it does not have a name it should be the direct type name + token = Token::findsimplematch(endOfTypeDef, "eEnum2_t", tokenizer.list.back()); + ASSERT_EQUALS("eEnum2_t", token->str()); + // Search for the simplified stStructDef token and check its original Name + token = Token::findsimplematch(endOfTypeDef, "stStructDef", tokenizer.list.back()); + ASSERT_EQUALS("stStruct_t", token->originalName()); + // Search for the simplified short token and check its original Name, start from front to get the variable in the struct + token = Token::findsimplematch(tokenizer.list.front(), "short", tokenizer.list.back()); + ASSERT_EQUALS("int16_t", token->originalName()); + // Search for the simplified * token -> function pointer gets "(*" tokens infront of it + token = Token::findsimplematch(endOfTypeDef, "*", tokenizer.list.back()); + ASSERT_EQUALS("rFunctionPointer_fp", token->originalName()); + } }; REGISTER_TEST(TestSimplifyTypedef) diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 1c42d76fdf9..b3e0818d8e5 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -1413,6 +1413,53 @@ class TestSymbolDatabase : public TestFixture { ASSERT(p->valueType()->volatileness == 2); ASSERT(p->valueType()->reference == Reference::None); } + { + GET_SYMBOL_DB_C("typedef unsigned char uint8_t;\n uint8_t ubVar = 0;\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->volatileness == 0); + ASSERT(p->valueType()->originalTypeName == "uint8_t"); + ASSERT(p->valueType()->reference == Reference::None); + } + { + GET_SYMBOL_DB_C("typedef enum eEnumDef {CPPCHECK=0}eEnum_t;\n eEnum_t eVar = CPPCHECK;\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->volatileness == 0); + ASSERT(p->valueType()->originalTypeName == "eEnum_t"); + ASSERT(p->valueType()->reference == Reference::None); + } + { + GET_SYMBOL_DB_C("typedef unsigned char uint8_t;\n typedef struct stStructDef {uint8_t ubTest;}stStruct_t;\n stStruct_t stVar;\n"); + const Variable* p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->volatileness == 0); + ASSERT(p->valueType()->originalTypeName == "uint8_t"); + ASSERT(p->valueType()->reference == Reference::None); + p = db->getVariableFromVarId(2); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->volatileness == 0); + ASSERT(p->valueType()->originalTypeName == "stStruct_t"); + ASSERT(p->valueType()->reference == Reference::None); + } + { + GET_SYMBOL_DB_C("typedef int (*ubFunctionPointer_fp)(int);\n void test(ubFunctionPointer_fp functionPointer);\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 1); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->volatileness == 0); + ASSERT(p->valueType()->originalTypeName == "ubFunctionPointer_fp"); + ASSERT(p->valueType()->reference == Reference::None); + } } void VariableValueTypeTemplate() { From c6853dc60916d47f1adbc92a74e98bb66f6eb29d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 14 Feb 2024 21:08:58 +0100 Subject: [PATCH 03/15] createrelease: specify commands to check ids (#5987) --- createrelease | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/createrelease b/createrelease index 2e5828b4c90..71498659bf3 100755 --- a/createrelease +++ b/createrelease @@ -7,7 +7,12 @@ # # check every isPremiumEnabled call: # - every id should be in --errorlist +# git grep 'isPremiumEnabled[(]"' | sed 's/.*isPremiumEnabled[(]"//' | sed 's/".*//' | sort | uniq > ids1.txt +# ./cppcheck --errorlist | grep ' id="' | sed 's/.* id="//' | sed 's/".*//' | sort | uniq > ids2.txt +# diff -y ids1.txt ids2.txt # - premiumaddon: check coverage.py +# python3 coverage.py --id ; sort ids-*.txt | uniq > ~/cppcheck/ids3.txt +# diff -y ids2.txt ids3.txt # # Windows installer: # - ensure latest build was successful From 23d3f5c82bc39a948f9589ccafa999a6661e7e52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Thu, 15 Feb 2024 15:19:45 +0100 Subject: [PATCH 04/15] oss-fuzz/type2.cpp: avoid usage of expensive `std::ostringstream` (#5986) --- oss-fuzz/type2.cpp | 95 +++++++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 35 deletions(-) diff --git a/oss-fuzz/type2.cpp b/oss-fuzz/type2.cpp index 0fe4ce343c4..6cd3591ec88 100644 --- a/oss-fuzz/type2.cpp +++ b/oss-fuzz/type2.cpp @@ -19,7 +19,6 @@ #include "type2.h" #include -#include static int getValue(const uint8_t *data, size_t dataSize, uint8_t maxValue, bool *done = nullptr) { @@ -54,19 +53,20 @@ static std::string generateExpression2_lvalue(const uint8_t *data, size_t dataSi static std::string generateExpression2_Op(const uint8_t *data, size_t dataSize, uint8_t numberOfGlobalConstants) { - std::ostringstream code; + std::string code; switch (getValue(data, dataSize, 3)) { case 0: - code << generateExpression2_lvalue(data, dataSize); + code += generateExpression2_lvalue(data, dataSize); break; case 1: - code << "globalconstant" << (1 + getValue(data, dataSize, numberOfGlobalConstants)); + code += "globalconstant"; + code += (1 + getValue(data, dataSize, numberOfGlobalConstants)); break; case 2: - code << (getValue(data, dataSize, 0x80) * 0x80 + getValue(data, dataSize, 0x80)); + code += (getValue(data, dataSize, 0x80) * 0x80 + getValue(data, dataSize, 0x80)); break; } - return code.str(); + return code; } static std::string generateExpression2_Expr(const uint8_t *data, size_t dataSize, uint8_t numberOfGlobalConstants, int depth=0) @@ -130,12 +130,14 @@ static std::string generateExpression2_conditionalCode(const std::string &indent size_t dataSize, uint8_t numberOfGlobalConstants) { - std::ostringstream code; + std::string code; if (indent.empty()) - code << functionStart(); - else - code << indent << "{\n"; + code += functionStart(); + else { + code += indent; + code += "{\n"; + } for (int line = 0; line < 4 || indent.empty(); ++line) { bool done = false; @@ -150,37 +152,60 @@ static std::string generateExpression2_conditionalCode(const std::string &indent ((type1 >= 5) ? mostLikelyType : type1); if (type2 == 0) { - code << indent << " var" << getValue(data, dataSize, 5) << "=" << generateExpression2_Expr(data, dataSize, numberOfGlobalConstants) << ";\n"; + code += indent; + code += " var"; + code += getValue(data, dataSize, 5); + code += "="; + code += generateExpression2_Expr(data, dataSize, numberOfGlobalConstants); + code += ";\n"; } else if (type2 == 1) { - code << indent << " if (" << generateExpression2_Cond(data, dataSize, numberOfGlobalConstants) << ")\n"; - code << generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); + code += indent; + code += " if ("; + code += generateExpression2_Cond(data, dataSize, numberOfGlobalConstants); + code += ")\n"; + code += generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); } else if (type2 == 2) { - code << indent << " if (" << generateExpression2_Cond(data, dataSize, numberOfGlobalConstants) << ")\n"; - code << generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); - code << indent << " else\n"; - code << generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); + code += indent; + code += " if ("; + code += generateExpression2_Cond(data, dataSize, numberOfGlobalConstants); + code += ")\n"; + code += generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); + code += indent; + code += " else\n"; + code += generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); } else if (type2 == 3) { - code << indent << " while (" << generateExpression2_Cond(data, dataSize, numberOfGlobalConstants) << ")\n"; - code << generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); + code += indent; + code += " while ("; + code += generateExpression2_Cond(data, dataSize, numberOfGlobalConstants); + code += ")\n"; + code += generateExpression2_conditionalCode(indent + " ", data, dataSize, numberOfGlobalConstants); } else if (type2 == 4) { - code << indent << " return " << generateExpression2_Expr(data, dataSize, numberOfGlobalConstants) << ";\n"; - if (indent.empty()) - code << "}\n\n" << functionStart(); + code += indent; + code += " return "; + code += generateExpression2_Expr(data, dataSize, numberOfGlobalConstants); + code += ";\n"; + if (indent.empty()) { + code += "}\n\n"; + code += functionStart(); + } else break; } } - if (!indent.empty()) - code << indent << "}\n"; - else - code << " return 0;\n}\n"; - return code.str(); + if (!indent.empty()) { + code += indent; + code += "}\n"; + } + else { + code += " return 0;\n}\n"; + } + return code; } std::string generateCode2(const uint8_t *data, size_t dataSize) { - std::ostringstream code; + std::string code; // create global constants constexpr uint8_t numberOfGlobalConstants = 0; @@ -192,15 +217,15 @@ std::string generateCode2(const uint8_t *data, size_t dataSize) } */ - code << "int var1 = 1;\n" - "int var2 = 0;\n" - "int var3 = 1;\n" - "int var4 = 0;\n" - "int var5 = -1;\n\n"; + code += "int var1 = 1;\n" + "int var2 = 0;\n" + "int var3 = 1;\n" + "int var4 = 0;\n" + "int var5 = -1;\n\n"; - code << generateExpression2_conditionalCode("", data, dataSize, numberOfGlobalConstants); + code += generateExpression2_conditionalCode("", data, dataSize, numberOfGlobalConstants); - return code.str(); + return code; } From 95235cade8c1298c6dde8d612bb7506d4857ebe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Fri, 16 Feb 2024 10:12:06 +0100 Subject: [PATCH 05/15] add `test/cli/fuzz_test.py` to easily integrate oss-fuzz findings into tests (#5985) This adds a Python test which processes input files from a folder and checks that they do not cause any crashes. This will later be extended to include timeouts as well. --- lib/checkfunctions.cpp | 2 +- lib/checkother.cpp | 2 +- lib/checkuninitvar.cpp | 2 +- lib/programmemory.cpp | 2 +- lib/tokenlist.cpp | 2 +- ...ash-26edfe9761d3b681c841dfe80398847dee332f83 | Bin 0 -> 18 bytes ...ash-3ea64296c8518edb538e0047c3eba0792d5deeba | Bin 0 -> 103 bytes ...ash-7ead2ccf9be8b03b2d9c8c82891f58081390a560 | Bin 0 -> 106 bytes ...ash-9ef938bba7d752386e24f2438c73cec66f6b972b | 12 ++++++++++++ ...ash-e4a26f2d7d0a73836bf086f54e48204d8914b95a | Bin 0 -> 159 bytes test/cli/fuzz_test.py | 16 ++++++++++++++++ 11 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 test/cli/fuzz-crash/crash-26edfe9761d3b681c841dfe80398847dee332f83 create mode 100644 test/cli/fuzz-crash/crash-3ea64296c8518edb538e0047c3eba0792d5deeba create mode 100644 test/cli/fuzz-crash/crash-7ead2ccf9be8b03b2d9c8c82891f58081390a560 create mode 100644 test/cli/fuzz-crash/crash-9ef938bba7d752386e24f2438c73cec66f6b972b create mode 100644 test/cli/fuzz-crash/crash-e4a26f2d7d0a73836bf086f54e48204d8914b95a create mode 100644 test/cli/fuzz_test.py diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index 7ce557bfc92..5aa979b0bcf 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -766,7 +766,7 @@ void CheckFunctions::useStandardLibrary() continue; // 3. we expect idx incrementing by 1 - const bool inc = stepToken->str() == "++" && stepToken->astOperand1()->varId() == idxVarId; + const bool inc = stepToken->str() == "++" && stepToken->astOperand1() && stepToken->astOperand1()->varId() == idxVarId; const bool plusOne = stepToken->isBinaryOp() && stepToken->str() == "+=" && stepToken->astOperand1()->varId() == idxVarId && stepToken->astOperand2()->str() == "1"; diff --git a/lib/checkother.cpp b/lib/checkother.cpp index af2ca4ea432..35e514dc0f2 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1938,7 +1938,7 @@ void CheckOther::checkIncompleteStatement() continue; if (isVoidStmt(tok)) continue; - if (mTokenizer->isCPP() && tok->str() == "&" && !(tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->isIntegral())) + if (mTokenizer->isCPP() && tok->str() == "&" && !(tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->isIntegral())) // Possible archive continue; const bool inconclusive = tok->isConstOp(); diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 8458ffe4d5c..e4038adfbf9 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1287,7 +1287,7 @@ const Token* CheckUninitVar::isVariableUsage(const Token *vartok, const Library& if (Token::Match((derefValue ? derefValue : vartok)->astParent(), "(|=") && astIsRhs(derefValue ? derefValue : vartok)) { const Token *rhstok = derefValue ? derefValue : vartok; const Token *lhstok = rhstok->astParent()->astOperand1(); - const Variable *lhsvar = lhstok->variable(); + const Variable *lhsvar = lhstok ? lhstok->variable() : nullptr; if (lhsvar && lhsvar->isReference() && lhsvar->nameToken() == lhstok) return nullptr; } diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 6b082514f14..b5558233206 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -320,7 +320,7 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke else pm.setIntValue(tok, 0, then); } - } else if (tok->exprId() > 0) { + } else if (tok && tok->exprId() > 0) { if (endTok && findExpressionChanged(tok, tok->next(), endTok, settings, true)) return; pm.setIntValue(tok, 0, then); diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index a0706491dac..b6e312625d9 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -960,7 +960,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state) Token* const curlyBracket = squareBracket->link()->next(); squareBracket->astOperand1(curlyBracket); state.op.push(squareBracket); - tok = curlyBracket->link()->next(); + tok = curlyBracket->link() ? curlyBracket->link()->next() : nullptr; continue; } } diff --git a/test/cli/fuzz-crash/crash-26edfe9761d3b681c841dfe80398847dee332f83 b/test/cli/fuzz-crash/crash-26edfe9761d3b681c841dfe80398847dee332f83 new file mode 100644 index 0000000000000000000000000000000000000000..37965deed0be75554c596307860cf4987f3c8b3a GIT binary patch literal 18 Zcma#%W-y3lU{J6rF3C*N%izjW001LL1TX*q literal 0 HcmV?d00001 diff --git a/test/cli/fuzz-crash/crash-3ea64296c8518edb538e0047c3eba0792d5deeba b/test/cli/fuzz-crash/crash-3ea64296c8518edb538e0047c3eba0792d5deeba new file mode 100644 index 0000000000000000000000000000000000000000..f096de3bf78f2d3cfd6f9fdd8db97552501f0059 GIT binary patch literal 103 zcmc~S%Tvfr%*@l!k{00sXR-T(jq literal 0 HcmV?d00001 diff --git a/test/cli/fuzz-crash/crash-7ead2ccf9be8b03b2d9c8c82891f58081390a560 b/test/cli/fuzz-crash/crash-7ead2ccf9be8b03b2d9c8c82891f58081390a560 new file mode 100644 index 0000000000000000000000000000000000000000..80a938891ac6ecaf058992612cecd407a43a606d GIT binary patch literal 106 zcmW-ZI|_g>6a-V}6l)i;@q<;&NkWPgDo-$i#5CgFUEOZjVWcGNQ8rWSTZ5C75q%#l sX;n&*Gvp&+IZhaXqXpYe7%Ze|>i^>%9lQjfqg?@I&exe38yS1_3u%iPR{#J2 literal 0 HcmV?d00001 diff --git a/test/cli/fuzz-crash/crash-9ef938bba7d752386e24f2438c73cec66f6b972b b/test/cli/fuzz-crash/crash-9ef938bba7d752386e24f2438c73cec66f6b972b new file mode 100644 index 00000000000..cf4921c19c7 --- /dev/null +++ b/test/cli/fuzz-crash/crash-9ef938bba7d752386e24f2438c73cec66f6b972b @@ -0,0 +1,12 @@ +#include +sho main() +{ + std::veCtor items(2); + stdtryector::iterator iter; + for (iter -= items.begin(); i&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ter != items.end();) { + if (*iter == 2) { + iter = items.erase//(iter); + } else { + } + } +} diff --git a/test/cli/fuzz-crash/crash-e4a26f2d7d0a73836bf086f54e48204d8914b95a b/test/cli/fuzz-crash/crash-e4a26f2d7d0a73836bf086f54e48204d8914b95a new file mode 100644 index 0000000000000000000000000000000000000000..89b9bf0f48b6c7dbef2981c39f35a120410c64ba GIT binary patch literal 159 zcmd1gXJBAp1mcpS%DfVV+{Da0jhy^+O|EJ#1t7=-iX}!H$6AAw00EmqrZre1Ex$-X zBU8av!N6J}Q^7{T*jgbwO-)-{6D$kTni#E}84FfW;usuk9~4r80D=gn6`TpyS(I8* LT2unHrIrf-yLu`4 literal 0 HcmV?d00001 diff --git a/test/cli/fuzz_test.py b/test/cli/fuzz_test.py new file mode 100644 index 00000000000..91f1dc84a9f --- /dev/null +++ b/test/cli/fuzz_test.py @@ -0,0 +1,16 @@ +import os +from testutils import cppcheck + +__script_dir = os.path.dirname(os.path.abspath(__file__)) + + +def test_fuzz_crash(): + failures = {} + + fuzz_crash_dir = os.path.join(__script_dir, 'fuzz-crash') + for f in os.listdir(fuzz_crash_dir): + ret, stdout, _ = cppcheck(['-q', '--enable=all', '--inconclusive', f], cwd=fuzz_crash_dir) + if ret != 0: + failures[f] = stdout + + assert failures == {} From 20b3792c29fd7b21ab12916e4606704e578c2d56 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Sat, 17 Feb 2024 16:00:56 -0600 Subject: [PATCH 06/15] Fix 12371: C++20: Requires clause on a constructor (#5972) --- lib/tokenize.cpp | 3 ++- test/testtokenize.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index eaf999979fd..98345dd31f9 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6344,7 +6344,8 @@ void Tokenizer::removeMacrosInGlobalScope() while (Token::Match(tok2, "%type% (") && tok2->isUpperCaseName()) tok2 = tok2->linkAt(1)->next(); - if (Token::Match(tok, "%name% (") && Token::Match(tok2, "%name% *|&|::|<| %name%") && !Token::Match(tok2, "namespace|class|struct|union|private:|protected:|public:")) + if (Token::Match(tok, "%name% (") && Token::Match(tok2, "%name% *|&|::|<| %name%") && + !Token::Match(tok2, "requires|namespace|class|struct|union|private:|protected:|public:")) unknownMacroError(tok); if (Token::Match(tok, "%type% (") && Token::Match(tok2, "%type% (") && !Token::Match(tok2, "noexcept|throw") && isFunctionHead(tok2->next(), ":;{")) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 03b780eab47..6fa10173b07 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -409,6 +409,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(checkRefQualifiers); TEST_CASE(checkConditionBlock); TEST_CASE(checkUnknownCircularVar); + TEST_CASE(checkRequires); // #9052 TEST_CASE(noCrash1); @@ -7559,6 +7560,12 @@ class TestTokenizer : public TestFixture { "}\n")); } + void checkRequires() + { + ASSERT_NO_THROW(tokenizeAndStringify("template\n" + "struct X { X(U) requires true {} };\n")); + } + void noCrash1() { ASSERT_NO_THROW(tokenizeAndStringify( "struct A {\n" From 3057ae8aa076ff2c1d29988cb453649937dd78e3 Mon Sep 17 00:00:00 2001 From: orbitcowboy Date: Sun, 18 Feb 2024 07:58:51 +0100 Subject: [PATCH 07/15] windows.cfg: Added more defines (#5993) --- cfg/windows.cfg | 120 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 3 deletions(-) diff --git a/cfg/windows.cfg b/cfg/windows.cfg index 63b88dc2af0..fcb9e52106c 100644 --- a/cfg/windows.cfg +++ b/cfg/windows.cfg @@ -16895,8 +16895,6 @@ HFONT CreateFont( - - @@ -16917,8 +16915,124 @@ HFONT CreateFont( - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0c0c1dfbf3f4fb31a0f8aeeff6aff89aa3fb3aac Mon Sep 17 00:00:00 2001 From: orbitcowboy Date: Sun, 18 Feb 2024 11:14:25 +0100 Subject: [PATCH 08/15] std.cfg: Added configuration for std::ifstream functions (#5994) Support has been added for: std::ifstream::bad(), std::ifstream::fail() and std::ifstream::good() --- cfg/std.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cfg/std.cfg b/cfg/std.cfg index 7fb77addfd3..5603161142d 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -6509,7 +6509,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -6523,14 +6523,14 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + false - + From f06b989420d4ad22715a384d223fd74564d338cb Mon Sep 17 00:00:00 2001 From: orbitcowboy Date: Sun, 18 Feb 2024 13:45:30 +0100 Subject: [PATCH 09/15] std.cfg: Added support for more functions from (#5995) --- cfg/std.cfg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cfg/std.cfg b/cfg/std.cfg index 5603161142d..61e0fa69675 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -6509,28 +6509,28 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + false - + false - + false - + From 80504486750b2e6a891218b0704741276943c402 Mon Sep 17 00:00:00 2001 From: Swasti Shrivastava <37058682+swasti16@users.noreply.github.com> Date: Sun, 18 Feb 2024 22:09:31 +0530 Subject: [PATCH 10/15] Fix 12448: False positive: misra-config about unknown variable after struct keyword (#5991) --- addons/misra.py | 4 ++++ addons/test/misra/misra-test.c | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/addons/misra.py b/addons/misra.py index ae3cf59c8bc..62a87666490 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -3327,6 +3327,9 @@ def misra_config(self, data): end_token = tok.link while tok != end_token: tok = tok.next + if tok.str == 'sizeof' and tok.next.str == '(': + tok = tok.next.link + continue if tok.str == "(" and tok.isCast: tok = tok.link continue @@ -4254,6 +4257,7 @@ def setSuppressionList(self, suppressionlist): self.addSuppressedRule(ruleNum) def report_config_error(self, location, errmsg): + errmsg = 'Because of missing configuration, misra checking is incomplete. There can be false negatives! ' + errmsg cppcheck_severity = 'error' error_id = 'config' if self.settings.verify: diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index d1ece87f2b2..fc0abdab7ca 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -2035,3 +2035,13 @@ static void misra_22_10(void) f = strtod(inStr, NULL_PTR); if(errno != 0) {} } + +// #12448 +static void check_misra_config(void) +{ + if (sizeof(struct bar) == 0U) {} //no warning + if (sizeof(int abc) == 0U) {} //no warning + if (sizeof(xyz) == 0U) {} //no warning + if (sizeof(const pqr) == 0U) {} //no warning + if (sizeof(const int* const pqrs) == 0U) {} //no-warning +} From 4e66b59d7951846671406c0f23e9ae6912037ab4 Mon Sep 17 00:00:00 2001 From: orbitcowboy Date: Sun, 18 Feb 2024 18:12:47 +0100 Subject: [PATCH 11/15] std.cfg: Added support for std::quoted() (#5996) --- cfg/std.cfg | 29 +++++++++++++++++++++++++++-- test/cfg/std.cpp | 14 ++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/cfg/std.cfg b/cfg/std.cfg index 61e0fa69675..707b51f145f 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -6428,7 +6428,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun std::istringstream& std::istringstream::get (char* s, streamsize n, char delim); stream buffer (3) std::istringstream& std::istringstream::get (streambuf& sb); std::istringstream& std::istringstream::get (streambuf& sb, char delim);--> - false @@ -6566,6 +6566,31 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun 0: + + + + + + false + + + + + + + + @@ -8303,7 +8328,7 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init - + false diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp index 4fab6bb6957..2b4aa12134a 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -53,6 +53,20 @@ #include #endif +// https://en.cppreference.com/w/cpp/io/manip/quoted +void uninitvar_std_quoted(std::stringstream &ss, const std::string &input, const char delim, const char escape) +{ + ss << std::quoted(input); + ss << std::quoted(input, delim); + ss << std::quoted(input, delim, escape); + char delimChar; + // cppcheck-suppress uninitvar + ss << std::quoted(input, delimChar); + char escapeChar; + // cppcheck-suppress uninitvar + ss << std::quoted(input, delim, escapeChar); +} + int zerodiv_ldexp() { int i = std::ldexp(0.0, 42.0); From 9e7337bbff57ec696fabcf91dbadf4941552a9e0 Mon Sep 17 00:00:00 2001 From: orbitcowboy Date: Sun, 18 Feb 2024 20:40:51 +0100 Subject: [PATCH 12/15] std.cfg: Added support for std::[oi]fstream::is_open() (#5997) --- cfg/std.cfg | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cfg/std.cfg b/cfg/std.cfg index 707b51f145f..faf23d8f992 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -6536,6 +6536,13 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false + + + + + + false + From 685c7b5ef321437e333eb549aeba2779fc1bae7a Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 19 Feb 2024 15:34:10 +0100 Subject: [PATCH 13/15] Add test for #8690 (#5999) --- test/cfg/std.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp index 2b4aa12134a..766c3b08efb 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -25,6 +25,7 @@ #define __STDC_WANT_LIB_EXT1__ 1 #include #include +#include #include #include #include @@ -4950,3 +4951,9 @@ void unique_lock_const_ref(std::mutex& m) { std::unique_lock lock(m); } + +void eraseIteratorOutOfBounds_std_deque(std::deque& x) // #8690 +{ + // cppcheck-suppress eraseIteratorOutOfBounds + x.erase(x.end()); +} \ No newline at end of file From 1fb3f1ecd27aded5b2bd3ce44a95059a0e698075 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 19 Feb 2024 17:01:25 +0100 Subject: [PATCH 14/15] Fix #12446 FN cstyleCast with scope operator (#5989) --- lib/checkother.cpp | 17 +++++++++++++++-- test/testother.cpp | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 35e514dc0f2..8663d7f2237 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -313,13 +313,26 @@ void CheckOther::warningOldStylePointerCast() tok = scope->bodyStart; for (; tok && tok != scope->bodyEnd; tok = tok->next()) { // Old style pointer casting.. - if (!Token::Match(tok, "( const|volatile| const|volatile|class|struct| %type% * *| *| const|&| ) (| %name%|%num%|%bool%|%char%|%str%|&")) + if (tok->str() != "(") continue; + const Token* castTok = tok->next(); + while (Token::Match(castTok, "const|volatile|class|struct|union|%type%|::")) { + castTok = castTok->next(); + if (Token::simpleMatch(castTok, "<") && castTok->link()) + castTok = castTok->link()->next(); + } + if (castTok == tok->next() || !Token::simpleMatch(castTok, "*")) + continue; + while (Token::Match(castTok, "*|const|&")) + castTok = castTok->next(); + if (!Token::Match(castTok, ") (| %name%|%num%|%bool%|%char%|%str%|&")) + continue; + if (Token::Match(tok->previous(), "%type%")) continue; // skip first "const" in "const Type* const" - while (Token::Match(tok->next(), "const|volatile|class|struct")) + while (Token::Match(tok->next(), "const|volatile|class|struct|union")) tok = tok->next(); const Token* typeTok = tok->next(); // skip second "const" in "const Type* const" diff --git a/test/testother.cpp b/test/testother.cpp index 2c949a47877..3f938af2e85 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1895,6 +1895,22 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:2]: (style) C-style pointer casting\n" "[test.cpp:3]: (style) C-style pointer casting\n", errout.str()); + + // #12446 + checkOldStylePointerCast("namespace N { struct S {}; }\n" + "union U {\n" + " int i;\n" + " char c[4];\n" + "};\n" + "void f(void* p) {\n" + " auto ps = (N::S*)p;\n" + " auto pu = (union U*)p;\n" + " auto pv = (std::vector*)(p);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7]: (style) C-style pointer casting\n" + "[test.cpp:8]: (style) C-style pointer casting\n" + "[test.cpp:9]: (style) C-style pointer casting\n", + errout.str()); } #define checkInvalidPointerCast(...) checkInvalidPointerCast_(__FILE__, __LINE__, __VA_ARGS__) From 49ce02fd0ca0f2ac7b2b2dab7eff4751b1fc360b Mon Sep 17 00:00:00 2001 From: olabetskyi <153490942+olabetskyi@users.noreply.github.com> Date: Mon, 19 Feb 2024 18:15:50 +0200 Subject: [PATCH 15/15] Fix #12449: dump file: Add "isOperator" and "isExplicit" to Function (#5990) --- lib/symboldatabase.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 6cd1d519454..a14b78e7015 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -4281,6 +4281,10 @@ void SymbolDatabase::printXml(std::ostream &out) const outs += accessControlToString(function->access); outs +="\""; } + if (function->isOperator()) + outs += " isOperator=\"true\""; + if (function->isExplicit()) + outs += " isExplicit=\"true\""; if (function->hasOverrideSpecifier()) outs += " hasOverrideSpecifier=\"true\""; if (function->hasFinalSpecifier())