Fix #11401 nullpointer dereference with alignof (#4601)

* checknullpointer: Don't report dereference with alignof

* Refactor unevaluating operator check in checknullpointer

Unifying these ensures the different checks treat the operators the
same.

* Fix FP with _Alignof and null pointer

Just like alignof, _Alignof does not evaluate its operand.

* CheckNullPointer: Also support compiler specific alignof

This fixes #11401 which is about __alignof__. For good measure, also add
the microsoft extensions __alignof and _alignof.
This commit is contained in:
Rikard Falkeborn 2022-11-27 09:20:19 +01:00 committed by GitHub
parent 8465d901c8
commit 52264b9c26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 5 deletions

View File

@ -150,8 +150,9 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown) const
return isPointerDeRef(tok, unknown, mSettings);
}
static bool isUnevaluated(const Token* tok) {
return tok && Token::Match(tok->previous(), "sizeof|decltype (");
static bool isUnevaluatedOperator(const Token* tok)
{
return Token::Match(tok, "sizeof|decltype|typeid|typeof|alignof|_Alignof|_alignof|__alignof|__alignof__ (");
}
bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Settings *settings)
@ -190,7 +191,8 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Set
return false;
// Dereferencing pointer..
if (parent->isUnaryOp("*") && !isUnevaluated(parent->astParent())) {
const Token* grandParent = parent->astParent();
if (parent->isUnaryOp("*") && !(grandParent && isUnevaluatedOperator(grandParent->previous()))) {
// declaration of function pointer
if (tok->variable() && tok->variable()->nameToken() == tok)
return false;
@ -288,7 +290,7 @@ void CheckNullPointer::nullPointerByDeRefAndChec()
const bool printInconclusive = (mSettings->certainty.isEnabled(Certainty::inconclusive));
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
if (Token::Match(tok, "sizeof|decltype|typeid|typeof (")) {
if (isUnevaluatedOperator(tok)) {
tok = tok->next()->link();
continue;
}
@ -347,7 +349,7 @@ void CheckNullPointer::nullConstantDereference()
tok = scope->function->token; // Check initialization list
for (; tok != scope->bodyEnd; tok = tok->next()) {
if (Token::Match(tok, "sizeof|decltype|typeid|typeof ("))
if (isUnevaluatedOperator(tok))
tok = tok->next()->link();
else if (Token::simpleMatch(tok, "* 0")) {

View File

@ -153,6 +153,7 @@ private:
TEST_CASE(scanf_with_invalid_va_argument);
TEST_CASE(nullpointer_in_return);
TEST_CASE(nullpointer_in_typeid);
TEST_CASE(nullpointer_in_alignof); // #11401
TEST_CASE(nullpointer_in_for_loop);
TEST_CASE(nullpointerDelete);
TEST_CASE(nullpointerSubFunction);
@ -3413,7 +3414,48 @@ private:
" return typeid(*c) == typeid(*c);\n"
"}", true);
ASSERT_EQUALS("", errout.str());
}
void nullpointer_in_alignof() // #11401
{
check("size_t foo() {\n"
" char* c = 0;\n"
" return alignof(*c);\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("size_t foo() {\n"
" return alignof(*0);\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void foo(int *p) {\n"
" f(alignof(*p));\n"
" if (p) {}\n"
" return;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("size_t foo() {\n"
" char* c = 0;\n"
" return _Alignof(*c);\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("size_t foo() {\n"
" return _alignof(*0);\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("size_t foo() {\n"
" return __alignof(*0);\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("size_t foo() {\n"
" return __alignof__(*0);\n"
"}", true);
ASSERT_EQUALS("", errout.str());
}
void nullpointer_in_for_loop() {
@ -4350,6 +4392,15 @@ private:
" f(NULL);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
ctu("size_t f(int* p) {\n"
" size_t len = alignof(*p);\n"
" return len;\n"
"}\n"
"void g() {\n"
" f(NULL);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
};