Skip to content

Commit 1516cd2

Browse files
Partial fix for #15048: shiftNegative for conditional value (#8884)
1 parent 2c5bf92 commit 1516cd2

3 files changed

Lines changed: 43 additions & 18 deletions

File tree

‎lib/checkother.cpp‎

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3530,9 +3530,11 @@ void CheckOtherImpl::redundantCopyError(const Token *tok,const std::string& varn
35303530
// Checking for shift by negative values
35313531
//---------------------------------------------------------------------------
35323532

3533-
static bool isNegative(const Token *tok, const Settings &settings)
3533+
static const ValueFlow::Value* isNegative(const Token *tok, const Settings &settings)
35343534
{
3535-
return tok->valueType() && tok->valueType()->sign == ValueType::SIGNED && tok->getValueLE(-1LL, settings);
3535+
if (!tok->valueType() || tok->valueType()->sign != ValueType::SIGNED)
3536+
return nullptr;
3537+
return tok->getValueLE(-1LL, settings);
35363538
}
35373539

35383540
void CheckOtherImpl::checkNegativeBitwiseShift()
@@ -3568,24 +3570,28 @@ void CheckOtherImpl::checkNegativeBitwiseShift()
35683570
if (ternary)
35693571
continue;
35703572

3571-
// Get negative rhs value. preferably a value which doesn't have 'condition'.
3572-
if (portability && isNegative(tok->astOperand1(), mSettings))
3573-
negativeBitwiseShiftError(tok, 1);
3574-
else if (isNegative(tok->astOperand2(), mSettings))
3575-
negativeBitwiseShiftError(tok, 2);
3573+
const ValueFlow::Value* value = isNegative(tok->astOperand1(), mSettings); // lhs
3574+
if (portability && value)
3575+
negativeBitwiseShiftError(tok, true, value);
3576+
else {
3577+
value = isNegative(tok->astOperand2(), mSettings); // rhs
3578+
if (value)
3579+
negativeBitwiseShiftError(tok, false, value);
3580+
}
35763581
}
35773582
}
35783583

35793584

3580-
void CheckOtherImpl::negativeBitwiseShiftError(const Token *tok, int op)
3585+
void CheckOtherImpl::negativeBitwiseShiftError(const Token *tok, bool isLHS, const ValueFlow::Value* v)
35813586
{
3582-
if (op == 1)
3583-
// LHS - this is used by intention in various software, if it
3584-
// is used often in a project and works as expected then this is
3585-
// a portability issue
3586-
reportError(tok, Severity::portability, "shiftNegativeLHS", "Shifting a negative value is technically undefined behaviour", CWE758, Certainty::normal);
3587-
else // RHS
3588-
reportError(tok, Severity::error, "shiftNegative", "Shifting by a negative value is undefined behaviour", CWE758, Certainty::normal);
3587+
// LHS - this is used by intention in various software, if it
3588+
// is used often in a project and works as expected then this is
3589+
// a portability issue
3590+
const char* id = isLHS ? "shiftNegativeLHS" : "shiftNegative";
3591+
const std::string msg = isLHS ? "Shifting a negative value is technically undefined behaviour" : "Shifting by a negative value is undefined behaviour";
3592+
const Severity severity = isLHS ? Severity::portability : (v && v->errorSeverity() && !v->conditional ? Severity::error : Severity::warning);
3593+
const ErrorPath errorPath = getErrorPath(tok, v, msg);
3594+
reportError(errorPath, severity, id, msg, CWE758, Certainty::normal);
35893595
}
35903596

35913597
//---------------------------------------------------------------------------
@@ -4946,8 +4952,8 @@ void CheckOther::getErrorMessages(ErrorLogger& errorLogger, const Settings &sett
49464952
c.zerodivError(nullptr, nullptr);
49474953
c.misusedScopeObjectError(nullptr, "varname");
49484954
c.invalidPointerCastError(nullptr, "float *", "double *", false, false);
4949-
c.negativeBitwiseShiftError(nullptr, 1);
4950-
c.negativeBitwiseShiftError(nullptr, 2);
4955+
c.negativeBitwiseShiftError(nullptr, true);
4956+
c.negativeBitwiseShiftError(nullptr, false);
49514957
c.raceAfterInterlockedDecrementError(nullptr);
49524958
c.invalidFreeError(nullptr, "malloc", false);
49534959
c.overlappingWriteUnion(nullptr);

‎lib/checkother.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ class CPPCHECKLIB CheckOtherImpl : public CheckImpl {
310310
void unsignedPositiveError(const Token *tok, const ValueFlow::Value *v, const std::string &varname);
311311
void pointerPositiveError(const Token *tok, const ValueFlow::Value *v);
312312
void suspiciousSemicolonError(const Token *tok);
313-
void negativeBitwiseShiftError(const Token *tok, int op);
313+
void negativeBitwiseShiftError(const Token *tok, bool isLHS, const ValueFlow::Value *v = nullptr);
314314
void redundantCopyError(const Token *tok, const std::string &varname);
315315
void incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean);
316316
void varFuncNullUBError(const Token *tok);

‎test/testother.cpp‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ class TestOther : public TestFixture {
231231
TEST_CASE(checkRedundantCopy);
232232

233233
TEST_CASE(checkNegativeShift);
234+
TEST_CASE(checkNegativeShiftErrorPath);
234235

235236
TEST_CASE(incompleteArrayFill);
236237

@@ -10537,6 +10538,24 @@ class TestOther : public TestFixture {
1053710538
ASSERT_EQUALS("", errout_str());
1053810539
}
1053910540

10541+
void checkNegativeShiftErrorPath() {
10542+
setMultiline();
10543+
Settings s = settings1;
10544+
s.templateLocation = "{file}:{line}:note:{info}\n";
10545+
10546+
check("int f(int i, bool b) {\n"
10547+
" int s = -1;\n"
10548+
" if (b)\n"
10549+
" return i;\n"
10550+
" return i << s;\n"
10551+
"}\n", dinit(CheckOptions, $.settings = &s));
10552+
ASSERT_EQUALS("[test.cpp:5:14]: warning: Shifting by a negative value is undefined behaviour [shiftNegative]\n"
10553+
"[test.cpp:2:14]: note: Assignment 's=-1', assigned value is -1\n"
10554+
"[test.cpp:3:9]: note: Assuming condition is false\n"
10555+
"[test.cpp:5:14]: note: Shifting by a negative value is undefined behaviour\n",
10556+
errout_str());
10557+
}
10558+
1054010559
void incompleteArrayFill() {
1054110560
check("void f() {\n"
1054210561
" int a[5];\n"

0 commit comments

Comments
 (0)