Ejemplo n.º 1
0
void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
                                   CheckerContext &C, bool IsBind) const {
  // Generate an error node.
  ExplodedNode *N = C.generateSink(State);
  if (!N)
    return;

  // We know that 'location' cannot be non-null.  This is what
  // we call an "explicit" null dereference.
  if (!BT_null)
    BT_null.reset(new BuiltinBug("Dereference of null pointer"));

  SmallString<100> buf;
  SmallVector<SourceRange, 2> Ranges;

  // Walk through lvalue casts to get the original expression
  // that syntactically caused the load.
  if (const Expr *expr = dyn_cast<Expr>(S))
    S = expr->IgnoreParenLValueCasts();

  const MemRegion *sourceR = 0;

  if (IsBind) {
    if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) {
      if (BO->isAssignmentOp())
        S = BO->getRHS();
    } else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
      assert(DS->isSingleDecl() && "We process decls one by one");
      if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
        if (const Expr *Init = VD->getAnyInitializer())
          S = Init;
    }
  }

  switch (S->getStmtClass()) {
  case Stmt::ArraySubscriptExprClass: {
    llvm::raw_svector_ostream os(buf);
    os << "Array access";
    const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
    sourceR = AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
                             State.getPtr(), N->getLocationContext());
    os << " results in a null pointer dereference";
    break;
  }
  case Stmt::UnaryOperatorClass: {
    llvm::raw_svector_ostream os(buf);
    os << "Dereference of null pointer";
    const UnaryOperator *U = cast<UnaryOperator>(S);
    sourceR = AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
                             State.getPtr(), N->getLocationContext(), true);
    break;
  }
  case Stmt::MemberExprClass: {
    const MemberExpr *M = cast<MemberExpr>(S);
    if (M->isArrow()) {
      llvm::raw_svector_ostream os(buf);
      os << "Access to field '" << M->getMemberNameInfo()
         << "' results in a dereference of a null pointer";
      sourceR = AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
                               State.getPtr(), N->getLocationContext(), true);
    }
    break;
  }
  case Stmt::ObjCIvarRefExprClass: {
    const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
    if (const DeclRefExpr *DR =
        dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) {
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        llvm::raw_svector_ostream os(buf);
        os << "Instance variable access (via '" << VD->getName()
           << "') results in a null pointer dereference";
      }
    }
    Ranges.push_back(IV->getSourceRange());
    break;
  }
  default:
    break;
  }

  BugReport *report =
    new BugReport(*BT_null,
                  buf.empty() ? BT_null->getDescription() : buf.str(),
                  N);

  bugreporter::addTrackNullOrUndefValueVisitor(N, bugreporter::GetDerefExpr(N),
                                               report);

  for (SmallVectorImpl<SourceRange>::iterator
       I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
    report->addRange(*I);

  if (sourceR) {
    report->markInteresting(sourceR);
    report->markInteresting(State->getRawSVal(loc::MemRegionVal(sourceR)));
  }

  C.EmitReport(report);
}
Ejemplo n.º 2
0
bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
                                        BugReport &report, bool IsArg) {
  if (!S || !N)
    return false;

  if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
    S = OVE->getSourceExpr();

  if (IsArg) {
    assert(isa<CallEnter>(N->getLocation()) && "Tracking arg but not at call");
  } else {
    // Walk through nodes until we get one that matches the statement exactly.
    do {
      const ProgramPoint &pp = N->getLocation();
      if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
        if (ps->getStmt() == S)
          break;
      } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) {
        if (CEE->getCalleeContext()->getCallSite() == S)
          break;
      }
      N = N->getFirstPred();
    } while (N);

    if (!N)
      return false;
  }
  
  ProgramStateRef state = N->getState();

  // See if the expression we're interested refers to a variable. 
  // If so, we can track both its contents and constraints on its value.
  if (const Expr *Ex = dyn_cast<Expr>(S)) {
    // Strip off parens and casts. Note that this will never have issues with
    // C++ user-defined implicit conversions, because those have a constructor
    // or function call inside.
    Ex = Ex->IgnoreParenCasts();
    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
      // FIXME: Right now we only track VarDecls because it's non-trivial to
      // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812>
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        ProgramStateManager &StateMgr = state->getStateManager();
        MemRegionManager &MRMgr = StateMgr.getRegionManager();
        const VarRegion *R = MRMgr.getVarRegion(VD, N->getLocationContext());

        // Mark both the variable region and its contents as interesting.
        SVal V = state->getRawSVal(loc::MemRegionVal(R));

        // If the value matches the default for the variable region, that
        // might mean that it's been cleared out of the state. Fall back to
        // the full argument expression (with casts and such intact).
        if (IsArg) {
          bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
          if (!UseArgValue) {
            const SymbolRegionValue *SRV =
              dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
            if (SRV)
              UseArgValue = (SRV->getRegion() == R);
          }
          if (UseArgValue)
            V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
        }

        report.markInteresting(R);
        report.markInteresting(V);
        report.addVisitor(new UndefOrNullArgVisitor(R));

        // If the contents are symbolic, find out when they became null.
        if (V.getAsLocSymbol()) {
          BugReporterVisitor *ConstraintTracker
            = new TrackConstraintBRVisitor(cast<DefinedSVal>(V), false);
          report.addVisitor(ConstraintTracker);
        }

        report.addVisitor(new FindLastStoreBRVisitor(V, R));
        return true;
      }
    }
  }

  // If the expression does NOT refer to a variable, we can still track
  // constraints on its contents.
  SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());

  // Uncomment this to find cases where we aren't properly getting the
  // base value that was dereferenced.
  // assert(!V.isUnknownOrUndef());

  // Is it a symbolic value?
  if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
    // At this point we are dealing with the region's LValue.
    // However, if the rvalue is a symbolic region, we should track it as well.
    SVal RVal = state->getSVal(L->getRegion());
    const MemRegion *RegionRVal = RVal.getAsRegion();
    report.addVisitor(new UndefOrNullArgVisitor(L->getRegion()));


    if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
      report.markInteresting(RegionRVal);
      report.addVisitor(new TrackConstraintBRVisitor(
        loc::MemRegionVal(RegionRVal), false));
    }
  } else {
    // Otherwise, if the value came from an inlined function call,
    // we should at least make sure that function isn't pruned in our output.
    if (const Expr *E = dyn_cast<Expr>(S))
      S = E->IgnoreParenCasts();
    ReturnVisitor::addVisitorIfNecessary(N, S, report);
  }

  return true;
}
Ejemplo n.º 3
0
bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode,
                                        const Stmt *S,
                                        BugReport &report, bool IsArg) {
  if (!S || !ErrorNode)
    return false;

  if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
    S = OVE->getSourceExpr();

  const ExplodedNode *N = ErrorNode;

  const Expr *Inner = 0;
  if (const Expr *Ex = dyn_cast<Expr>(S)) {
    Ex = Ex->IgnoreParenCasts();
    if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex))
      Inner = Ex;
  }

  if (IsArg) {
    assert(N->getLocation().getAs<CallEnter>() && "Tracking arg but not at call");
  } else {
    // Walk through nodes until we get one that matches the statement exactly.
    // Alternately, if we hit a known lvalue for the statement, we know we've
    // gone too far (though we can likely track the lvalue better anyway).
    do {
      const ProgramPoint &pp = N->getLocation();
      if (Optional<PostStmt> ps = pp.getAs<PostStmt>()) {
        if (ps->getStmt() == S || ps->getStmt() == Inner)
          break;
      } else if (Optional<CallExitEnd> CEE = pp.getAs<CallExitEnd>()) {
        if (CEE->getCalleeContext()->getCallSite() == S ||
            CEE->getCalleeContext()->getCallSite() == Inner)
          break;
      }
      N = N->getFirstPred();
    } while (N);

    if (!N)
      return false;
  }
  
  ProgramStateRef state = N->getState();

  // See if the expression we're interested refers to a variable. 
  // If so, we can track both its contents and constraints on its value.
  if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) {
    const MemRegion *R = 0;

    // First check if this is a DeclRefExpr for a C++ reference type.
    // For those, we want the location of the reference.
    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Inner)) {
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        if (VD->getType()->isReferenceType()) {
          ProgramStateManager &StateMgr = state->getStateManager();
          MemRegionManager &MRMgr = StateMgr.getRegionManager();
          R = MRMgr.getVarRegion(VD, N->getLocationContext());
        }
      }
    }

    // For all other cases, find the location by scouring the ExplodedGraph.
    if (!R) {
      // Find the ExplodedNode where the lvalue (the value of 'Ex')
      // was computed.  We need this for getting the location value.
      const ExplodedNode *LVNode = N;
      while (LVNode) {
        if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) {
          if (P->getStmt() == Inner)
            break;
        }
        LVNode = LVNode->getFirstPred();
      }
      assert(LVNode && "Unable to find the lvalue node.");
      ProgramStateRef LVState = LVNode->getState();
      R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion();
    }

    if (R) {
      // Mark both the variable region and its contents as interesting.
      SVal V = state->getRawSVal(loc::MemRegionVal(R));

      // If the value matches the default for the variable region, that
      // might mean that it's been cleared out of the state. Fall back to
      // the full argument expression (with casts and such intact).
      if (IsArg) {
        bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
        if (!UseArgValue) {
          const SymbolRegionValue *SRV =
            dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
          if (SRV)
            UseArgValue = (SRV->getRegion() == R);
        }
        if (UseArgValue)
          V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
      }

      report.markInteresting(R);
      report.markInteresting(V);
      report.addVisitor(new UndefOrNullArgVisitor(R));

      if (isa<SymbolicRegion>(R)) {
        TrackConstraintBRVisitor *VI =
          new TrackConstraintBRVisitor(loc::MemRegionVal(R), false);
        report.addVisitor(VI);
      }

      // If the contents are symbolic, find out when they became null.
      if (V.getAsLocSymbol()) {
        BugReporterVisitor *ConstraintTracker =
          new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false);
        report.addVisitor(ConstraintTracker);

        // Add visitor, which will suppress inline defensive checks.
        if (ErrorNode->getState()->isNull(V).isConstrainedTrue()) {
          BugReporterVisitor *IDCSuppressor =
            new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(),
                                                     ErrorNode);
          report.addVisitor(IDCSuppressor);
        }
      }

      if (Optional<KnownSVal> KV = V.getAs<KnownSVal>())
        report.addVisitor(new FindLastStoreBRVisitor(*KV, R));
      return true;
    }
  }

  // If the expression is not an "lvalue expression", we can still
  // track the constraints on its contents.
  SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());

  // If the value came from an inlined function call, we should at least make
  // sure that function isn't pruned in our output.
  if (const Expr *E = dyn_cast<Expr>(S))
    S = E->IgnoreParenCasts();
  ReturnVisitor::addVisitorIfNecessary(N, S, report);

  // Uncomment this to find cases where we aren't properly getting the
  // base value that was dereferenced.
  // assert(!V.isUnknownOrUndef());
  // Is it a symbolic value?
  if (Optional<loc::MemRegionVal> L = V.getAs<loc::MemRegionVal>()) {
    // At this point we are dealing with the region's LValue.
    // However, if the rvalue is a symbolic region, we should track it as well.
    SVal RVal = state->getSVal(L->getRegion());
    const MemRegion *RegionRVal = RVal.getAsRegion();
    report.addVisitor(new UndefOrNullArgVisitor(L->getRegion()));

    if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
      report.markInteresting(RegionRVal);
      report.addVisitor(new TrackConstraintBRVisitor(
        loc::MemRegionVal(RegionRVal), false));
    }
  }

  return true;
}
void bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
                                        BugReport &report) {
  if (!S || !N)
    return;

  ProgramStateManager &StateMgr = N->getState()->getStateManager();

  // Walk through nodes until we get one that matches the statement exactly.
  while (N) {
    const ProgramPoint &pp = N->getLocation();
    if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
      if (ps->getStmt() == S)
        break;
    } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) {
      if (CEE->getCalleeContext()->getCallSite() == S)
        break;
    }
    N = N->getFirstPred();
  }

  if (!N)
    return;
  
  ProgramStateRef state = N->getState();

  // See if the expression we're interested refers to a variable. 
  // If so, we can track both its contents and constraints on its value.
  if (const Expr *Ex = dyn_cast<Expr>(S)) {
    // Strip off parens and casts. Note that this will never have issues with
    // C++ user-defined implicit conversions, because those have a constructor
    // or function call inside.
    Ex = Ex->IgnoreParenCasts();
    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
      // FIXME: Right now we only track VarDecls because it's non-trivial to
      // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812>
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        const VarRegion *R =
          StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());

        // Mark both the variable region and its contents as interesting.
        SVal V = state->getRawSVal(loc::MemRegionVal(R));
        report.markInteresting(R);
        report.markInteresting(V);

        // If the contents are symbolic, find out when they became null.
        if (V.getAsLocSymbol()) {
          BugReporterVisitor *ConstraintTracker
            = new TrackConstraintBRVisitor(cast<loc::MemRegionVal>(V), false);
          report.addVisitor(ConstraintTracker);
        }

        report.addVisitor(new FindLastStoreBRVisitor(V, R));
        return;
      }
    }
  }

  // If the expression does NOT refer to a variable, we can still track
  // constraints on its contents.
  SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());

  // Uncomment this to find cases where we aren't properly getting the
  // base value that was dereferenced.
  // assert(!V.isUnknownOrUndef());

  // Is it a symbolic value?
  if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
    const MemRegion *Base = L->getRegion()->getBaseRegion();
    if (isa<SymbolicRegion>(Base)) {
      report.markInteresting(Base);
      report.addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(Base),
                                                      false));
    }
  } else {
    // Otherwise, if the value came from an inlined function call,
    // we should at least make sure that function isn't pruned in our output.
    ReturnVisitor::addVisitorIfNecessary(N, S, report);
  }
}