diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:11:37 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:11:37 +0000 |
| commit | 461a67fa15370a9ec88f8f8a240bf7c123bb2029 (patch) | |
| tree | 6942083d7d56bba40ec790a453ca58ad3baf6832 /lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | |
| parent | 75c3240472ba6ac2669ee72ca67eb72d4e2851fc (diff) | |
Notes
Diffstat (limited to 'lib/StaticAnalyzer/Core/BugReporterVisitors.cpp')
| -rw-r--r-- | lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 96 |
1 files changed, 64 insertions, 32 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index d00182a871c1..7304d789431e 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -11,7 +11,7 @@ // enhance the diagnostics reported for a bug. // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/Analysis/CFGStmtMap.h" @@ -42,48 +42,80 @@ bool bugreporter::isDeclRefExprToReference(const Expr *E) { return false; } +/// Given that expression S represents a pointer that would be dereferenced, +/// try to find a sub-expression from which the pointer came from. +/// This is used for tracking down origins of a null or undefined value: +/// "this is null because that is null because that is null" etc. +/// We wipe away field and element offsets because they merely add offsets. +/// We also wipe away all casts except lvalue-to-rvalue casts, because the +/// latter represent an actual pointer dereference; however, we remove +/// the final lvalue-to-rvalue cast before returning from this function +/// because it demonstrates more clearly from where the pointer rvalue was +/// loaded. Examples: +/// x->y.z ==> x (lvalue) +/// foo()->y.z ==> foo() (rvalue) const Expr *bugreporter::getDerefExpr(const Stmt *S) { - // Pattern match for a few useful cases: - // a[0], p->f, *p const Expr *E = dyn_cast<Expr>(S); if (!E) return nullptr; - E = E->IgnoreParenCasts(); while (true) { - if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E)) { - assert(B->isAssignmentOp()); - E = B->getLHS()->IgnoreParenCasts(); - continue; - } - else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) { - if (U->getOpcode() == UO_Deref) - return U->getSubExpr()->IgnoreParenCasts(); - } - else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { - if (ME->isImplicitAccess()) { - return ME; - } else if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) { - return ME->getBase()->IgnoreParenCasts(); + if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { + if (CE->getCastKind() == CK_LValueToRValue) { + // This cast represents the load we're looking for. + break; + } + E = CE->getSubExpr(); + } else if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E)) { + // Pointer arithmetic: '*(x + 2)' -> 'x') etc. + if (B->getType()->isPointerType()) { + if (B->getLHS()->getType()->isPointerType()) { + E = B->getLHS(); + } else if (B->getRHS()->getType()->isPointerType()) { + E = B->getRHS(); + } else { + break; + } } else { - // If we have a member expr with a dot, the base must have been - // dereferenced. - return getDerefExpr(ME->getBase()); + // Probably more arithmetic can be pattern-matched here, + // but for now give up. + break; + } + } else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) { + if (U->getOpcode() == UO_Deref || U->getOpcode() == UO_AddrOf || + (U->isIncrementDecrementOp() && U->getType()->isPointerType())) { + // Operators '*' and '&' don't actually mean anything. + // We look at casts instead. + E = U->getSubExpr(); + } else { + // Probably more arithmetic can be pattern-matched here, + // but for now give up. + break; } } - else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) { - return IvarRef->getBase()->IgnoreParenCasts(); - } - else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) { - return getDerefExpr(AE->getBase()); - } - else if (isa<DeclRefExpr>(E)) { - return E; + // Pattern match for a few useful cases: a[0], p->f, *p etc. + else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + E = ME->getBase(); + } else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) { + E = IvarRef->getBase(); + } else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) { + E = AE->getBase(); + } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) { + E = PE->getSubExpr(); + } else { + // Other arbitrary stuff. + break; } - break; } - return nullptr; + // Special case: remove the final lvalue-to-rvalue cast, but do not recurse + // deeper into the sub-expression. This way we return the lvalue from which + // our pointer rvalue was loaded. + if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) + if (CE->getCastKind() == CK_LValueToRValue) + E = CE->getSubExpr(); + + return E; } const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) { @@ -1509,7 +1541,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr, // For non-assignment operations, we require that we can understand // both the LHS and RHS. if (LhsString.empty() || RhsString.empty() || - !BinaryOperator::isComparisonOp(Op)) + !BinaryOperator::isComparisonOp(Op) || Op == BO_Cmp) return nullptr; // Should we invert the strings if the LHS is not a variable name? |
