forked from OSchip/llvm-project
[clang-tidy] bugprone-infinite-loop: Fix false positives with volatile addresses.
Low-level code may occasionally deal with direct access by concrete addresses such as 0x1234. Values at these addresses act like globals: they can change at any time. They typically wear volatile qualifiers. Suppress all warnings on loops with conditions that involve casting anything to a pointer-to-...-pointer-to-volatile type. The closely related bugprone-redundant-branch-condition check doesn't seem to be affected. Add a test just in case. Differential Revision: https://reviews.llvm.org/D108808
This commit is contained in:
parent
eeabd90efd
commit
dcde8fdeeb
|
@ -65,6 +65,17 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func, const Stmt *LoopStmt,
|
|||
ObjCIvarRefExpr, ObjCPropertyRefExpr, ObjCMessageExpr>(Cond)) {
|
||||
// FIXME: Handle MemberExpr.
|
||||
return true;
|
||||
} else if (const auto *CE = dyn_cast<CastExpr>(Cond)) {
|
||||
QualType T = CE->getType();
|
||||
while (true) {
|
||||
if (T.isVolatileQualified())
|
||||
return true;
|
||||
|
||||
if (!T->isAnyPointerType() && !T->isReferenceType())
|
||||
break;
|
||||
|
||||
T = T->getPointeeType();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -591,3 +591,34 @@ void test_structured_bindings_bad() {
|
|||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (x) are updated in the loop body [bugprone-infinite-loop]
|
||||
}
|
||||
}
|
||||
|
||||
void test_volatile_cast() {
|
||||
// This is a no-op cast. Clang ignores the qualifier, we should too.
|
||||
for (int i = 0; (volatile int)i < 10;) {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
|
||||
}
|
||||
}
|
||||
|
||||
void test_volatile_concrete_address(int i, int size) {
|
||||
// No warning. The value behind the volatile concrete address
|
||||
// is beyond our control. It may change at any time.
|
||||
for (; *((volatile int *)0x1234) < size;) {
|
||||
}
|
||||
|
||||
for (; *((volatile int *)(0x1234 + i)) < size;) {
|
||||
}
|
||||
|
||||
for (; **((volatile int **)0x1234) < size;) {
|
||||
}
|
||||
|
||||
volatile int *x = (volatile int *)0x1234;
|
||||
for (; *x < 10;) {
|
||||
}
|
||||
|
||||
// FIXME: This one should probably also be suppressed.
|
||||
// Whatever the developer is doing here, they can do that again anywhere else
|
||||
// which basically makes it a global.
|
||||
for (; *(int *)0x1234 < size;) {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (size) are updated in the loop body [bugprone-infinite-loop]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1387,3 +1387,13 @@ void relational_operator_reversed() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void volatile_concrete_address() {
|
||||
// No warning. The value behind the volatile concrete address
|
||||
// is beyond our control. It may change at any time.
|
||||
if (*(volatile int *)0x1234) {
|
||||
if (*(volatile int *)0x1234) {
|
||||
doSomething();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue