diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 4a8551a15..94ebd95b2 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -841,7 +841,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const ArrayInfo &arrayInfo valueFlowCheckArrayIndex(tok->next(), arrayInfo); } - else if (isPortabilityEnabled && tok->astParent() && tok->astParent()->str() == "+") { + else if (isPortabilityEnabled && !tok->isCasted() && tok->astParent() && tok->astParent()->str() == "+") { const ValueFlow::Value *index; if (tok == tok->astParent()->astOperand1()) index = tok->astParent()->astOperand2()->getMaxValue(false); diff --git a/lib/token.h b/lib/token.h index 010024267..1ede4fdb4 100644 --- a/lib/token.h +++ b/lib/token.h @@ -313,6 +313,12 @@ public: void isExpandedMacro(bool m) { setFlag(fIsExpandedMacro, m); } + bool isCasted() const { + return getFlag(fIsCasted); + } + void isCasted(bool c) { + setFlag(fIsCasted, c); + } bool isAttributeConstructor() const { return getFlag(fIsAttributeConstructor); } @@ -753,14 +759,15 @@ private: fIsLong = (1 << 3), fIsStandardType = (1 << 4), fIsExpandedMacro = (1 << 5), - fIsAttributeConstructor = (1 << 6), // __attribute__((constructor)) __attribute__((constructor(priority))) - fIsAttributeDestructor = (1 << 7), // __attribute__((destructor)) __attribute__((destructor(priority))) - fIsAttributeUnused = (1 << 8), // __attribute__((unused)) - fIsAttributePure = (1 << 9), // __attribute__((pure)) - fIsAttributeConst = (1 << 10), // __attribute__((const)) - fIsAttributeNothrow = (1 << 11), // __attribute__((nothrow)) - fIsDeclspecNothrow = (1 << 12), // __declspec(nothrow) - fIsAttributeUsed = (1 << 13) // __attribute__((used)) + fIsCasted = (1 << 6), + fIsAttributeConstructor = (1 << 7), // __attribute__((constructor)) __attribute__((constructor(priority))) + fIsAttributeDestructor = (1 << 8), // __attribute__((destructor)) __attribute__((destructor(priority))) + fIsAttributeUnused = (1 << 9), // __attribute__((unused)) + fIsAttributePure = (1 << 10), // __attribute__((pure)) + fIsAttributeConst = (1 << 11), // __attribute__((const)) + fIsAttributeNothrow = (1 << 12), // __attribute__((nothrow)) + fIsDeclspecNothrow = (1 << 13), // __declspec(nothrow) + fIsAttributeUsed = (1 << 14) // __attribute__((used)) }; unsigned int _flags; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 4f1b776ea..c05b2756e 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5004,6 +5004,7 @@ void Tokenizer::simplifyCasts() if (!tok->tokAt(2)->isUnsigned() && bits > 0) bits--; if (bits < 31 && value >= 0 && value < (1LL << bits)) { + tok->linkAt(1)->next()->isCasted(true); Token::eraseTokens(tok, tok->next()->link()->next()); } continue; @@ -5023,6 +5024,15 @@ void Tokenizer::simplifyCasts() // Remove cast.. Token::eraseTokens(tok, tok->next()->link()->next()); + // Set isCasted flag. + Token *tok2 = tok->next(); + if (!Token::Match(tok2, "%var% [|.")) + tok2->isCasted(true); + else { + // TODO: handle more complex expressions + tok2->next()->isCasted(true); + } + // Remove '* &' if (Token::simpleMatch(tok, "* &")) { tok->deleteNext(); @@ -5038,6 +5048,7 @@ void Tokenizer::simplifyCasts() // Replace pointer casts of 0.. "(char *)0" => "0" while (Token::Match(tok->next(), "( %type% %type%| * ) 0")) { + tok->linkAt(1)->next()->isCasted(true); Token::eraseTokens(tok, tok->next()->link()->next()); if (tok->str() == ")" && tok->link()->previous()) { // If there was another cast before this, go back @@ -5048,11 +5059,11 @@ void Tokenizer::simplifyCasts() if (Token::Match(tok->next(), "dynamic_cast|reinterpret_cast|const_cast|static_cast <")) { Token *tok2 = tok->linkAt(2); - - if (Token::simpleMatch(tok2, "> (")) - Token::eraseTokens(tok, tok2->next()); - else + if (!Token::simpleMatch(tok2, "> (")) break; + + tok2->tokAt(2)->isCasted(true); + Token::eraseTokens(tok, tok2->next()); } } } diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 6b0b96fe8..5f12c9ef0 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -2955,6 +2955,12 @@ private: " return a + 100;\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (portability) Undefined behaviour: Pointer arithmetic result does not point into or just past the end of the array.\n", errout.str()); + + check("void f() {\n" // #6350 - fp when there is cast of buffer + " wchar_t buf[64];\n" + " p = (unsigned char *) buf + sizeof (buf);\n" + "}", false, "6350.c", false); + ASSERT_EQUALS("", errout.str()); } void pointer_out_of_bounds_2() {