summaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorCsaba Dabis <dabis.csaba98@gmail.com>2019-08-22 02:57:59 +0000
committerCsaba Dabis <dabis.csaba98@gmail.com>2019-08-22 02:57:59 +0000
commit3a0426ea559d704305b6d1706341ad353b333d91 (patch)
tree3b4d390b333b1da53ab0822a78d959df32082f05 /lib/StaticAnalyzer
parenteff97972f9bf2e48217fe6ab7f92719a123ac1b7 (diff)
downloadclang-3a0426ea559d704305b6d1706341ad353b333d91.tar.gz
[analyzer] CastValueChecker: Model isa(), isa_and_nonnull()
Summary: - Reviewed By: NoQ Differential Revision: https://reviews.llvm.org/D66423 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@369615 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer')
-rw-r--r--lib/StaticAnalyzer/Checkers/CastValueChecker.cpp105
1 files changed, 100 insertions, 5 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp b/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
index 1580f7f31c..5c4daa3e42 100644
--- a/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
@@ -16,6 +16,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/DeclTemplate.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -30,7 +31,7 @@ using namespace ento;
namespace {
class CastValueChecker : public Checker<eval::Call> {
- enum class CallKind { Function, Method };
+ enum class CallKind { Function, Method, InstanceOf };
using CastCheck =
std::function<void(const CastValueChecker *, const CallEvent &Call,
@@ -45,6 +46,10 @@ public:
//
// 4) castAs: Has no parameter, the return value is non-null.
// 5) getAs: Has no parameter, the return value is null or non-null.
+ //
+ // We have two cases to check the parameter is an instance of the given type.
+ // 1) isa: The parameter is non-null, returns boolean.
+ // 2) isa_and_nonnull: The parameter is null or non-null, returns boolean.
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
@@ -63,7 +68,11 @@ private:
{{{"clang", "castAs"}, 0},
{&CastValueChecker::evalCastAs, CallKind::Method}},
{{{"clang", "getAs"}, 0},
- {&CastValueChecker::evalGetAs, CallKind::Method}}};
+ {&CastValueChecker::evalGetAs, CallKind::Method}},
+ {{{"llvm", "isa"}, 1},
+ {&CastValueChecker::evalIsa, CallKind::InstanceOf}},
+ {{{"llvm", "isa_and_nonnull"}, 1},
+ {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}};
void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
CheckerContext &C) const;
@@ -77,6 +86,10 @@ private:
CheckerContext &C) const;
void evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
CheckerContext &C) const;
+ void evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
+ CheckerContext &C) const;
+ void evalIsaAndNonNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
+ CheckerContext &C) const;
};
} // namespace
@@ -189,6 +202,42 @@ static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV,
getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
}
+static void addInstanceOfTransition(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
+ ProgramStateRef State, CheckerContext &C,
+ bool IsInstanceOf) {
+ const FunctionDecl *FD = Call.getDecl()->getAsFunction();
+ QualType CastToTy = FD->getTemplateSpecializationArgs()->get(0).getAsType();
+ QualType CastFromTy = getRecordType(Call.parameters()[0]->getType());
+
+ const MemRegion *MR = DV.getAsRegion();
+ const DynamicCastInfo *CastInfo =
+ getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
+
+ bool CastSucceeds;
+ if (CastInfo)
+ CastSucceeds = IsInstanceOf && CastInfo->succeeds();
+ else
+ CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
+
+ if (isInfeasibleCast(CastInfo, CastSucceeds)) {
+ C.generateSink(State, C.getPredecessor());
+ return;
+ }
+
+ // Store the type and the cast information.
+ bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
+ if (!IsKnownCast)
+ State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
+ Call.getResultType(), IsInstanceOf);
+
+ C.addTransition(
+ State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+ C.getSValBuilder().makeTruthVal(CastSucceeds)),
+ getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds,
+ IsKnownCast));
+}
+
//===----------------------------------------------------------------------===//
// Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null.
//===----------------------------------------------------------------------===//
@@ -278,6 +327,41 @@ void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
}
//===----------------------------------------------------------------------===//
+// Evaluating isa, isa_and_nonnull.
+//===----------------------------------------------------------------------===//
+
+void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
+ CheckerContext &C) const {
+ ProgramStateRef NonNullState, NullState;
+ std::tie(NonNullState, NullState) = C.getState()->assume(DV);
+
+ if (NonNullState) {
+ addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
+ addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
+ }
+
+ if (NullState) {
+ C.generateSink(NullState, C.getPredecessor());
+ }
+}
+
+void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
+ CheckerContext &C) const {
+ ProgramStateRef NonNullState, NullState;
+ std::tie(NonNullState, NullState) = C.getState()->assume(DV);
+
+ if (NonNullState) {
+ addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
+ addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
+ }
+
+ if (NullState) {
+ addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false);
+ }
+}
+
+//===----------------------------------------------------------------------===//
// Main logic to evaluate a call.
//===----------------------------------------------------------------------===//
@@ -287,12 +371,14 @@ bool CastValueChecker::evalCall(const CallEvent &Call,
if (!Lookup)
return false;
+ const CastCheck &Check = Lookup->first;
+ CallKind Kind = Lookup->second;
+
// We need to obtain the record type of the call's result to model it.
- if (!getRecordType(Call.getResultType())->isRecordType())
+ if (Kind != CallKind::InstanceOf &&
+ !getRecordType(Call.getResultType())->isRecordType())
return false;
- const CastCheck &Check = Lookup->first;
- CallKind Kind = Lookup->second;
Optional<DefinedOrUnknownSVal> DV;
switch (Kind) {
@@ -304,6 +390,15 @@ bool CastValueChecker::evalCall(const CallEvent &Call,
DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
break;
}
+ case CallKind::InstanceOf: {
+ // We need to obtain the only template argument to determinte the type.
+ const FunctionDecl *FD = Call.getDecl()->getAsFunction();
+ if (!FD || !FD->getTemplateSpecializationArgs())
+ return false;
+
+ DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
+ break;
+ }
case CallKind::Method:
const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call);
if (!InstanceCall)