Fix #11553 pop_back on empty container is UB (#4789)

This commit is contained in:
chrchr-github 2023-02-24 01:10:19 +01:00 committed by GitHub
parent ce3ba5c015
commit 50c8a0dbe1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 3 deletions

View File

@ -8574,7 +8574,6 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init
<function name="pop_back" action="pop"/>
<function name="push_front" action="push"/>
<function name="emplace_front" action="push"/>
<function name="pop_front" action="pop"/>
</size>
<access indexOperator="array-like">
<function name="at" yields="at_index"/>
@ -8594,6 +8593,9 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init
</container>
<container id="stdDeque" startPattern="std :: deque &lt;" inherits="stdVectorDeque">
<type unstable="erase insert"/>
<size>
<function name="pop_front" action="pop"/>
</size>
</container>
<container id="stdArray" startPattern="std :: array &lt;" inherits="stdContainer" opLessAllowed="true">
<size templateParameter="1">

View File

@ -97,6 +97,16 @@ static bool containerYieldsElement(const Library::Container* container, const To
return false;
}
static bool containerPopsElement(const Library::Container* container, const Token* parent)
{
if (Token::Match(parent, ". %name% (")) {
const Library::Container::Action action = container->getAction(parent->strAt(1));
if (contains({ Library::Container::Action::POP }, action))
return true;
}
return false;
}
static const Token* getContainerIndex(const Library::Container* container, const Token* parent)
{
if (Token::Match(parent, ". %name% (")) {
@ -148,8 +158,9 @@ void CheckStl::outOfBounds()
continue;
if (!value.errorSeverity() && !mSettings->severity.isEnabled(Severity::warning))
continue;
if (value.intvalue == 0 && (indexTok || (containerYieldsElement(container, parent) &&
!containerAppendsElement(container, parent)))) {
if (value.intvalue == 0 && (indexTok ||
(containerYieldsElement(container, parent) && !containerAppendsElement(container, parent)) ||
containerPopsElement(container, parent))) {
std::string indexExpr;
if (indexTok && !indexTok->hasKnownValue())
indexExpr = indexTok->expressionString();

View File

@ -123,6 +123,7 @@ private:
TEST_CASE(pushback13);
TEST_CASE(insert1);
TEST_CASE(insert2);
TEST_CASE(popback1);
TEST_CASE(stlBoundaries1);
TEST_CASE(stlBoundaries2);
@ -3061,6 +3062,31 @@ private:
ASSERT_EQUALS("", errout.str());
}
void popback1() { // #11553
check("void f() {\n"
" std::vector<int> v;\n"
" v.pop_back();\n"
" std::list<int> l;\n"
" l.pop_front();\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (error) Out of bounds access in expression 'v.pop_back()' because 'v' is empty.\n"
"[test.cpp:5]: (error) Out of bounds access in expression 'l.pop_front()' because 'l' is empty.\n",
errout.str());
check("void f(std::vector<int>& v) {\n"
" if (v.empty()) {}\n"
" v.pop_back();\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Either the condition 'v.empty()' is redundant or expression 'v.pop_back()' cause access out of bounds.\n",
errout.str());
check("void f(std::vector<int>& v) {\n"
" v.pop_back();\n"
" if (v.empty()) {}\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void stlBoundaries1() {
const std::string stlCont[] = {
"list", "set", "multiset", "map", "multimap"