Skip to content

Commit 8bc5ef4

Browse files
Merge pull request #2671 from SavchenkoValeriy/analyzer_cherry_picks_march_2020
Static analyzer cherrypicks 19
2 parents 73e4a09 + 867e86a commit 8bc5ef4

File tree

5 files changed

+82
-8
lines changed

5 files changed

+82
-8
lines changed

clang/lib/Analysis/CalledOnceCheck.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,12 @@ static constexpr unsigned EXPECTED_NUMBER_OF_BASIC_BLOCKS = 8;
4848
template <class T>
4949
using CFGSizedVector = llvm::SmallVector<T, EXPECTED_NUMBER_OF_BASIC_BLOCKS>;
5050
constexpr llvm::StringLiteral CONVENTIONAL_NAMES[] = {
51-
"completionHandler", "completion", "withCompletionHandler"};
51+
"completionHandler", "completion", "withCompletionHandler",
52+
"withCompletion", "completionBlock", "withCompletionBlock",
53+
"replyTo", "reply", "withReplyTo"};
5254
constexpr llvm::StringLiteral CONVENTIONAL_SUFFIXES[] = {
53-
"WithCompletionHandler", "WithCompletion"};
55+
"WithCompletionHandler", "WithCompletion", "WithCompletionBlock",
56+
"WithReplyTo", "WithReply"};
5457
constexpr llvm::StringLiteral CONVENTIONAL_CONDITIONS[] = {
5558
"error", "cancel", "shouldCall", "done", "OK", "success"};
5659

@@ -994,13 +997,15 @@ class CalledOnceChecker : public ConstStmtVisitor<CalledOnceChecker> {
994997
return hasConventionalSuffix(MethodSelector.getNameForSlot(0));
995998
}
996999

997-
return isConventional(MethodSelector.getNameForSlot(PieceIndex));
1000+
llvm::StringRef PieceName = MethodSelector.getNameForSlot(PieceIndex);
1001+
return isConventional(PieceName) || hasConventionalSuffix(PieceName);
9981002
}
9991003

10001004
bool shouldBeCalledOnce(const ParmVarDecl *Parameter) const {
10011005
return isExplicitlyMarked(Parameter) ||
10021006
(CheckConventionalParameters &&
1003-
isConventional(Parameter->getName()) &&
1007+
(isConventional(Parameter->getName()) ||
1008+
hasConventionalSuffix(Parameter->getName())) &&
10041009
isConventional(Parameter->getType()));
10051010
}
10061011

clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ class StdLibraryFunctionsChecker
508508
mutable FunctionSummaryMapType FunctionSummaryMap;
509509

510510
mutable std::unique_ptr<BugType> BT_InvalidArg;
511+
mutable bool SummariesInitialized = false;
511512

512513
static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
513514
return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
@@ -823,7 +824,7 @@ StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
823824

824825
void StdLibraryFunctionsChecker::initFunctionSummaries(
825826
CheckerContext &C) const {
826-
if (!FunctionSummaryMap.empty())
827+
if (SummariesInitialized)
827828
return;
828829

829830
SValBuilder &SVB = C.getSValBuilder();
@@ -2485,6 +2486,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
24852486
Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
24862487
Summary(EvalCallAsPure));
24872488
}
2489+
2490+
SummariesInitialized = true;
24882491
}
24892492

24902493
void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {

clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
2020
#include "llvm/ADT/FoldingSet.h"
2121
#include "llvm/ADT/ImmutableSet.h"
22+
#include "llvm/ADT/STLExtras.h"
23+
#include "llvm/Support/Compiler.h"
2224
#include "llvm/Support/raw_ostream.h"
2325

2426
using namespace clang;
@@ -1395,12 +1397,23 @@ class RangeConstraintManager : public RangedConstraintManager {
13951397
return EquivalenceClass::merge(getBasicVals(), F, State, LHS, RHS);
13961398
}
13971399

1398-
LLVM_NODISCARD inline ProgramStateRef setConstraint(ProgramStateRef State,
1399-
EquivalenceClass Class,
1400-
RangeSet Constraint) {
1400+
LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED static bool
1401+
areFeasible(ConstraintRangeTy Constraints) {
1402+
return llvm::none_of(
1403+
Constraints,
1404+
[](const std::pair<EquivalenceClass, RangeSet> &ClassConstraint) {
1405+
return ClassConstraint.second.isEmpty();
1406+
});
1407+
}
1408+
1409+
LLVM_NODISCARD ProgramStateRef setConstraint(ProgramStateRef State,
1410+
EquivalenceClass Class,
1411+
RangeSet Constraint) {
14011412
ConstraintRangeTy Constraints = State->get<ConstraintRange>();
14021413
ConstraintRangeTy::Factory &CF = State->get_context<ConstraintRange>();
14031414

1415+
assert(!Constraint.isEmpty() && "New constraint should not be empty");
1416+
14041417
// Add new constraint.
14051418
Constraints = CF.add(Constraints, Class, Constraint);
14061419

@@ -1413,9 +1426,18 @@ class RangeConstraintManager : public RangedConstraintManager {
14131426
for (EquivalenceClass DisequalClass : Class.getDisequalClasses(State)) {
14141427
RangeSet UpdatedConstraint =
14151428
getRange(State, DisequalClass).Delete(getBasicVals(), F, *Point);
1429+
1430+
// If we end up with at least one of the disequal classes to be
1431+
// constrainted with an empty range-set, the state is infeasible.
1432+
if (UpdatedConstraint.isEmpty())
1433+
return nullptr;
1434+
14161435
Constraints = CF.add(Constraints, DisequalClass, UpdatedConstraint);
14171436
}
14181437

1438+
assert(areFeasible(Constraints) && "Constraint manager shouldn't produce "
1439+
"a state with infeasible constraints");
1440+
14191441
return State->set<ConstraintRange>(Constraints);
14201442
}
14211443

clang/test/Analysis/PR49490.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %clang_analyze_cc1 -w -analyzer-checker=core -verify %s
2+
3+
// expected-no-diagnostics
4+
5+
struct toggle {
6+
bool value;
7+
};
8+
9+
toggle global_toggle;
10+
toggle get_global_toggle() { return global_toggle; }
11+
12+
int oob_access();
13+
14+
bool compare(toggle one, bool other) {
15+
if (one.value != other)
16+
return true;
17+
18+
if (one.value)
19+
oob_access();
20+
return true;
21+
}
22+
23+
bool coin();
24+
25+
void bar() {
26+
bool left = coin();
27+
bool right = coin();
28+
for (;;)
29+
compare(get_global_toggle(), left) && compare(get_global_toggle(), right);
30+
}

clang/test/SemaObjC/warn-called-once.m

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,20 @@ - (void)testWithCompletion:(void (^)(void))callback {
10361036
}
10371037
}
10381038

1039+
- (void)test:(int)cond fooWithReplyTo:(void (^)(void))handler {
1040+
if (cond) {
1041+
// expected-warning@-1{{completion handler is never called when taking false branch}}
1042+
handler();
1043+
}
1044+
}
1045+
1046+
- (void)test:(int)cond with:(void (^)(void))fooWithCompletionBlock {
1047+
if (cond) {
1048+
// expected-warning@-1{{completion handler is never called when taking false branch}}
1049+
fooWithCompletionBlock();
1050+
}
1051+
}
1052+
10391053
- (void)completion_handler_wrong_type:(int (^)(void))completionHandler {
10401054
// We don't want to consider completion handlers with non-void return types.
10411055
if ([self condition]) {

0 commit comments

Comments
 (0)