library: add attribute strlen-arg for <not-overlapping-data>

This commit is contained in:
Daniel Marjamäki 2021-07-09 13:25:01 +02:00
parent 17d5dc4d8a
commit ce58748690
6 changed files with 35 additions and 3 deletions

View File

@ -176,6 +176,9 @@
<optional> <optional>
<attribute name="size-arg"><data type="positiveInteger"/></attribute> <attribute name="size-arg"><data type="positiveInteger"/></attribute>
</optional> </optional>
<optional>
<attribute name="strlen-arg"><data type="positiveInteger"/></attribute>
</optional>
<empty/> <empty/>
</element> </element>
</optional> </optional>

View File

@ -4769,6 +4769,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<function name="strcpy,std::strcpy"> <function name="strcpy,std::strcpy">
<returnValue type="char *">arg1</returnValue> <returnValue type="char *">arg1</returnValue>
<noreturn>false</noreturn> <noreturn>false</noreturn>
<not-overlapping-data ptr1-arg="1" ptr2-arg="2" strlen-arg="2"/>
<leak-ignore/> <leak-ignore/>
<arg nr="1" direction="out"> <arg nr="1" direction="out">
<not-null/> <not-null/>

View File

@ -3438,15 +3438,35 @@ void CheckOther::checkOverlappingWrite()
continue; continue;
if (nonOverlappingData->ptr2Arg <= 0 || nonOverlappingData->ptr2Arg > args.size()) if (nonOverlappingData->ptr2Arg <= 0 || nonOverlappingData->ptr2Arg > args.size())
continue; 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; continue;
}
if (!args[nonOverlappingData->sizeArg-1]->hasKnownIntValue()) if (!args[nonOverlappingData->sizeArg-1]->hasKnownIntValue())
continue; continue;
const Token *buf1, *buf2; const Token *buf1, *buf2;
MathLib::bigint offset1, offset2; MathLib::bigint offset1, offset2;
if (!getBufAndOffset(args[nonOverlappingData->ptr1Arg-1], &buf1, &offset1)) if (!getBufAndOffset(ptr1, &buf1, &offset1))
continue; continue;
if (!getBufAndOffset(args[nonOverlappingData->ptr2Arg-1], &buf2, &offset2)) if (!getBufAndOffset(ptr2, &buf2, &offset2))
continue; continue;
ErrorPath errorPath; ErrorPath errorPath;

View File

@ -645,6 +645,7 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
nonOverlappingData.ptr1Arg = functionnode->IntAttribute("ptr1-arg", -1); nonOverlappingData.ptr1Arg = functionnode->IntAttribute("ptr1-arg", -1);
nonOverlappingData.ptr2Arg = functionnode->IntAttribute("ptr2-arg", -1); nonOverlappingData.ptr2Arg = functionnode->IntAttribute("ptr2-arg", -1);
nonOverlappingData.sizeArg = functionnode->IntAttribute("size-arg", -1); nonOverlappingData.sizeArg = functionnode->IntAttribute("size-arg", -1);
nonOverlappingData.strlenArg = functionnode->IntAttribute("strlen-arg", -1);
mNonOverlappingData[name] = nonOverlappingData; mNonOverlappingData[name] = nonOverlappingData;
} else if (functionnodename == "use-retval") { } else if (functionnodename == "use-retval") {
func.useretval = Library::UseRetValType::DEFAULT; func.useretval = Library::UseRetValType::DEFAULT;

View File

@ -172,6 +172,7 @@ public:
int ptr1Arg; int ptr1Arg;
int ptr2Arg; int ptr2Arg;
int sizeArg; int sizeArg;
int strlenArg;
}; };
const NonOverlappingData* getNonOverlappingData(const Token *ftok) const; const NonOverlappingData* getNonOverlappingData(const Token *ftok) const;

View File

@ -9361,6 +9361,12 @@ private:
" wmemcpy(a, a+1, 2u);\n" " wmemcpy(a, a+1, 2u);\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Overlapping read/write in wmemcpy() is undefined behavior\n", errout.str()); 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());
} }
}; };