library: add attribute strlen-arg for <not-overlapping-data>
This commit is contained in:
parent
17d5dc4d8a
commit
ce58748690
|
@ -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>
|
||||||
|
|
|
@ -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/>
|
||||||
|
|
|
@ -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;
|
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())
|
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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue