diff --git a/cfg/cppcheck-cfg.rng b/cfg/cppcheck-cfg.rng index 595afb2be..45cff6c91 100644 --- a/cfg/cppcheck-cfg.rng +++ b/cfg/cppcheck-cfg.rng @@ -176,6 +176,9 @@ + + + diff --git a/cfg/std.cfg b/cfg/std.cfg index c7b1b788f..2b06a8ec7 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -4769,6 +4769,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun arg1 false + diff --git a/lib/checkother.cpp b/lib/checkother.cpp index f41109da3..141665b22 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3438,15 +3438,35 @@ void CheckOther::checkOverlappingWrite() continue; if (nonOverlappingData->ptr2Arg <= 0 || nonOverlappingData->ptr2Arg > args.size()) continue; - if (nonOverlappingData->sizeArg <= 0 || nonOverlappingData->sizeArg > args.size()) + + const Token *ptr1 = args[nonOverlappingData->ptr1Arg - 1]; + if (ptr1->hasKnownIntValue() && ptr1->getKnownIntValue() == 0) + continue; + + const Token *ptr2 = args[nonOverlappingData->ptr2Arg - 1]; + if (ptr2->hasKnownIntValue() && ptr2->getKnownIntValue() == 0) + continue; + + // TODO: nonOverlappingData->strlenArg + if (nonOverlappingData->sizeArg <= 0 || nonOverlappingData->sizeArg > args.size()) { + if (nonOverlappingData->sizeArg == -1) { + ErrorPath errorPath; + const bool macro = true; + const bool pure = true; + const bool follow = true; + if (!isSameExpression(mTokenizer->isCPP(), macro, ptr1, ptr2, mSettings->library, pure, follow, &errorPath)) + continue; + overlappingWriteFunction(tok); + } continue; + } if (!args[nonOverlappingData->sizeArg-1]->hasKnownIntValue()) continue; const Token *buf1, *buf2; MathLib::bigint offset1, offset2; - if (!getBufAndOffset(args[nonOverlappingData->ptr1Arg-1], &buf1, &offset1)) + if (!getBufAndOffset(ptr1, &buf1, &offset1)) continue; - if (!getBufAndOffset(args[nonOverlappingData->ptr2Arg-1], &buf2, &offset2)) + if (!getBufAndOffset(ptr2, &buf2, &offset2)) continue; ErrorPath errorPath; diff --git a/lib/library.cpp b/lib/library.cpp index c7c4154c8..7d1ee95a1 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -645,6 +645,7 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co nonOverlappingData.ptr1Arg = functionnode->IntAttribute("ptr1-arg", -1); nonOverlappingData.ptr2Arg = functionnode->IntAttribute("ptr2-arg", -1); nonOverlappingData.sizeArg = functionnode->IntAttribute("size-arg", -1); + nonOverlappingData.strlenArg = functionnode->IntAttribute("strlen-arg", -1); mNonOverlappingData[name] = nonOverlappingData; } else if (functionnodename == "use-retval") { func.useretval = Library::UseRetValType::DEFAULT; diff --git a/lib/library.h b/lib/library.h index f452852f4..040a6c5b8 100644 --- a/lib/library.h +++ b/lib/library.h @@ -172,6 +172,7 @@ public: int ptr1Arg; int ptr2Arg; int sizeArg; + int strlenArg; }; const NonOverlappingData* getNonOverlappingData(const Token *ftok) const; diff --git a/test/testother.cpp b/test/testother.cpp index 594b36f43..2c914e947 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -9361,6 +9361,12 @@ private: " wmemcpy(a, a+1, 2u);\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Overlapping read/write in wmemcpy() is undefined behavior\n", errout.str()); + + // strcpy + check("void foo(char *ptr) {\n" + " strcpy(ptr, ptr);\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (error) Overlapping read/write in strcpy() is undefined behavior\n", errout.str()); } };