Пример #1
0
void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
                                     SVal lock) const {

  const MemRegion *lockR = lock.getAsRegion();
  if (!lockR)
    return;
  
  ProgramStateRef state = C.getState();

  if (const LockState *LState = state->get<LockMap>(lockR)) {
    if (LState->isUnlocked()) {
      if (!BT_doubleunlock)
        BT_doubleunlock.reset(new BugType(this, "Double unlocking",
                                          "Lock checker"));
      ExplodedNode *N = C.generateSink();
      if (!N)
        return;
      BugReport *Report = new BugReport(*BT_doubleunlock,
                                        "This lock has already been unlocked",
                                        N);
      Report->addRange(CE->getArg(0)->getSourceRange());
      C.emitReport(Report);
      return;
    } else if (LState->isDestroyed()) {
      reportUseDestroyedBug(C, CE);
      return;
    }
  }

  LockSetTy LS = state->get<LockSet>();

  // FIXME: Better analysis requires IPA for wrappers.

  if (!LS.isEmpty()) {
    const MemRegion *firstLockR = LS.getHead();
    if (firstLockR != lockR) {
      if (!BT_lor)
        BT_lor.reset(new BugType(this, "Lock order reversal", "Lock checker"));
      ExplodedNode *N = C.generateSink();
      if (!N)
        return;
      BugReport *report = new BugReport(*BT_lor,
                                        "This was not the most recently "
                                        "acquired lock. Possible lock order "
                                        "reversal",
                                        N);
      report->addRange(CE->getArg(0)->getSourceRange());
      C.emitReport(report);
      return;
    }
    // Record that the lock was released.
    state = state->set<LockSet>(LS.getTail());
  }

  state = state->set<LockMap>(lockR, LockState::getUnlocked());
  C.addTransition(state);
}
Пример #2
0
void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
                                                   CheckerContext &C) const {
  // Check if the method is annotated with analyzer_noreturn.
  if (const ObjCMethodDecl *MD = Msg.getDecl()) {
    MD = MD->getCanonicalDecl();
    if (MD->hasAttr<AnalyzerNoReturnAttr>()) {
      C.generateSink();
      return;
    }
  }

  // HACK: This entire check is to handle two messages in the Cocoa frameworks:
  // -[NSAssertionHandler
  //    handleFailureInMethod:object:file:lineNumber:description:]
  // -[NSAssertionHandler
  //    handleFailureInFunction:file:lineNumber:description:]
  // Eventually these should be annotated with __attribute__((noreturn)).
  // Because ObjC messages use dynamic dispatch, it is not generally safe to
  // assume certain methods can't return. In cases where it is definitely valid,
  // see if you can mark the methods noreturn or analyzer_noreturn instead of
  // adding more explicit checks to this method.

  if (!Msg.isInstanceMessage())
    return;

  const ObjCInterfaceDecl *Receiver = Msg.getReceiverInterface();
  if (!Receiver)
    return;
  if (!Receiver->getIdentifier()->isStr("NSAssertionHandler"))
    return;

  Selector Sel = Msg.getSelector();
  switch (Sel.getNumArgs()) {
  default:
    return;
  case 4:
    lazyInitKeywordSelector(HandleFailureInFunctionSel, C.getASTContext(),
                            "handleFailureInFunction", "file", "lineNumber",
                            "description", nullptr);
    if (Sel != HandleFailureInFunctionSel)
      return;
    break;
  case 5:
    lazyInitKeywordSelector(HandleFailureInMethodSel, C.getASTContext(),
                            "handleFailureInMethod", "object", "file",
                            "lineNumber", "description", nullptr);
    if (Sel != HandleFailureInMethodSel)
      return;
    break;
  }

  // If we got here, it's one of the messages we care about.
  C.generateSink();
}
Пример #3
0
void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
                                       CheckerContext &C) const {
  // Check for dereference of an undefined value.
  if (l.isUndef()) {
    if (ExplodedNode *N = C.generateSink()) {
      if (!BT_undef)
        BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value"));

      BugReport *report =
        new BugReport(*BT_undef, BT_undef->getDescription(), N);
      bugreporter::addTrackNullOrUndefValueVisitor(N,
                                                   bugreporter::GetDerefExpr(N),
                                                   report);
      report->disablePathPruning();
      C.EmitReport(report);
    }
    return;
  }

  DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);

  // Check for null dereferences.
  if (!isa<Loc>(location))
    return;

  ProgramStateRef state = C.getState();

  ProgramStateRef notNullState, nullState;
  llvm::tie(notNullState, nullState) = state->assume(location);

  // The explicit NULL case.
  if (nullState) {
    if (!notNullState) {
      reportBug(nullState, S, C);
      return;
    }

    // Otherwise, we have the case where the location could either be
    // null or not-null.  Record the error node as an "implicit" null
    // dereference.
    if (ExplodedNode *N = C.generateSink(nullState)) {
      ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() };
      dispatchEvent(event);
    }
  }

  // From this point forward, we know that the location is not null.
  C.addTransition(notNullState);
}
Пример #4
0
void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE,
                                     SVal Lock) const {

  const MemRegion *LockR = Lock.getAsRegion();
  if (!LockR)
    return;

  ProgramStateRef State = C.getState();

  const LockState *LState = State->get<LockMap>(LockR);
  if (!LState || LState->isUnlocked()) {
    State = State->set<LockMap>(LockR, LockState::getDestroyed());
    C.addTransition(State);
    return;
  }

  StringRef Message;

  if (LState->isLocked()) {
    Message = "This lock is still locked";
  } else {
    Message = "This lock has already been destroyed";
  }

  if (!BT_destroylock)
    BT_destroylock.reset(new BugType(this, "Destroy invalid lock",
                                     "Lock checker"));
  ExplodedNode *N = C.generateSink();
  if (!N)
    return;
  auto Report = llvm::make_unique<BugReport>(*BT_destroylock, Message, N);
  Report->addRange(CE->getArg(0)->getSourceRange());
  C.emitReport(std::move(Report));
}
void 
UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
                                             CheckerContext &C) const {
  const Expr *Index = A->getIdx();
  if (!C.getSVal(Index).isUndef())
    return;

  // Sema generates anonymous array variables for copying array struct fields.
  // Don't warn if we're in an implicitly-generated constructor.
  const Decl *D = C.getLocationContext()->getDecl();
  if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D))
    if (Ctor->isDefaulted())
      return;

  ExplodedNode *N = C.generateSink();
  if (!N)
    return;
  if (!BT)
    BT.reset(new BuiltinBug(this, "Array subscript is undefined"));

  // Generate a report for this bug.
  BugReport *R = new BugReport(*BT, BT->getName(), N);
  R->addRange(A->getIdx()->getSourceRange());
  bugreporter::trackNullOrUndefValue(N, A->getIdx(), *R);
  C.emitReport(R);
}
Пример #6
0
void VLASizeChecker::reportBug(VLASize_Kind Kind,
                               const Expr *SizeE,
                               ProgramStateRef State,
                               CheckerContext &C) const {
  // Generate an error node.
  ExplodedNode *N = C.generateSink(State);
  if (!N)
    return;

  if (!BT)
    BT.reset(new BuiltinBug(
        this, "Dangerous variable-length array (VLA) declaration"));

  SmallString<256> buf;
  llvm::raw_svector_ostream os(buf);
  os << "Declared variable-length array (VLA) ";
  switch (Kind) {
  case VLA_Garbage:
    os << "uses a garbage value as its size";
    break;
  case VLA_Zero:
    os << "has zero size";
    break;
  case VLA_Tainted:
    os << "has tainted size";
    break;
  }

  BugReport *report = new BugReport(*BT, os.str(), N);
  report->addRange(SizeE->getSourceRange());
  bugreporter::trackNullOrUndefValue(N, SizeE, *report);
  C.emitReport(report);
  return;
}
Пример #7
0
void PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE,
                                  SVal Lock) const {

  const MemRegion *LockR = Lock.getAsRegion();
  if (!LockR)
    return;

  ProgramStateRef State = C.getState();

  const struct LockState *LState = State->get<LockMap>(LockR);
  if (!LState || LState->isDestroyed()) {
    State = State->set<LockMap>(LockR, LockState::getUnlocked());
    C.addTransition(State);
    return;
  }

  StringRef Message;

  if (LState->isLocked()) {
    Message = "This lock is still being held";
  } else {
    Message = "This lock has already been initialized";
  }

  if (!BT_initlock)
    BT_initlock.reset(new BugType(this, "Init invalid lock",
                                  "Lock checker"));
  ExplodedNode *N = C.generateSink();
  if (!N)
    return;
  BugReport *Report = new BugReport(*BT_initlock, Message, N);
  Report->addRange(CE->getArg(0)->getSourceRange());
  C.emitReport(Report);
}
Пример #8
0
void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
                                    ProgramStateRef errorState,
                                    OOB_Kind kind) const {
  
  ExplodedNode *errorNode = checkerContext.generateSink(errorState);
  if (!errorNode)
    return;

  if (!BT)
    BT.reset(new BuiltinBug("Out-of-bound access"));

  // FIXME: This diagnostics are preliminary.  We should get far better
  // diagnostics for explaining buffer overruns.

  SmallString<256> buf;
  llvm::raw_svector_ostream os(buf);
  os << "Out of bound memory access ";
  switch (kind) {
  case OOB_Precedes:
    os << "(accessed memory precedes memory block)";
    break;
  case OOB_Excedes:
    os << "(access exceeds upper limit of memory block)";
    break;
  case OOB_Tainted:
    os << "(index is tainted)";
    break;
  }

  checkerContext.emitReport(new BugReport(*BT, os.str(), errorNode));
}
Пример #9
0
void IteratorChecker::handleComparison(CheckerContext &C, const SVal &RetVal,
                                       const SVal &LVal, const SVal &RVal,
                                       OverloadedOperatorKind Op) const {
  // Record the operands and the operator of the comparison for the next
  // evalAssume, if the result is a symbolic expression. If it is a concrete
  // value (only one branch is possible), then transfer the state between
  // the operands according to the operator and the result
  auto State = C.getState();
  if (const auto *Condition = RetVal.getAsSymbolicExpression()) {
    const auto *LPos = getIteratorPosition(State, LVal);
    const auto *RPos = getIteratorPosition(State, RVal);
    if (!LPos && !RPos)
      return;
    State = saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual);
    C.addTransition(State);
  } else if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
    if ((State = processComparison(
             State, getRegionOrSymbol(LVal), getRegionOrSymbol(RVal),
             (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) {
      C.addTransition(State);
    } else {
      C.generateSink(State, C.getPredecessor());
    }
  }
}
SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
                                                  const Expr* Arg,
                                                  bool IssueWarning) const {
  const ProgramState *State = C.getState();
  SVal AddrVal = State->getSVal(Arg->IgnoreParenCasts());
  Loc *AddrLoc = dyn_cast<Loc>(&AddrVal);

  if (!AddrLoc && !IssueWarning)
    return 0;

  // If the Expr is not a location, issue a warning.
  if (!AddrLoc) {
    assert(IssueWarning);
    if (ExplodedNode *N = C.generateSink(State)) {
      initBugType();
      BugReport *report = new BugReport(*BT, "Pointer argument is expected.",N);
      report->addRange(Arg->getSourceRange());
      C.EmitReport(report);
    }
    return 0;
  }

  SVal Val = State->getSVal(*AddrLoc);
  return Val.getAsSymbol();
}
Пример #11
0
void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
                                     CheckerContext &C) const {
  // TODO: Clean up the state.
  for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
         E = SymReaper.dead_end(); I != E; ++I) {
    SymbolRef Sym = *I;
    ProgramStateRef state = C.getState();
    const StreamState *SS = state->get<StreamMap>(Sym);
    // TODO: Shouldn't we have a continue here?
    if (!SS)
      return;

    if (SS->isOpened()) {
      ExplodedNode *N = C.generateSink();
      if (N) {
        if (!BT_ResourceLeak)
          BT_ResourceLeak.reset(new BuiltinBug("Resource Leak", 
                         "Opened File never closed. Potential Resource leak."));
        BugReport *R = new BugReport(*BT_ResourceLeak, 
                                     BT_ResourceLeak->getDescription(), N);
        C.emitReport(R);
      }
    }
  }
}
Пример #12
0
ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
                                               ProgramStateRef state,
                                               CheckerContext &C) const {
  SymbolRef Sym =
    state->getSVal(CE->getArg(0), C.getLocationContext()).getAsSymbol();
  if (!Sym)
    return state;
  
  const StreamState *SS = state->get<StreamMap>(Sym);

  // If the file stream is not tracked, return.
  if (!SS)
    return state;
  
  // Check: Double close a File Descriptor could cause undefined behaviour.
  // Conforming to man-pages
  if (SS->isClosed()) {
    ExplodedNode *N = C.generateSink();
    if (N) {
      if (!BT_doubleclose)
        BT_doubleclose.reset(new BuiltinBug("Double fclose",
                                        "Try to close a file Descriptor already"
                                        " closed. Cause undefined behaviour."));
      BugReport *R = new BugReport(*BT_doubleclose,
                                   BT_doubleclose->getDescription(), N);
      C.emitReport(R);
    }
    return NULL;
  }
  
  // Close the File Descriptor.
  return state->set<StreamMap>(Sym, StreamState::getClosed(CE));
}
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
                                              ProgramStateRef state,
                                              const ObjCMethodCall &Msg) const {
  ASTContext &Ctx = C.getASTContext();
  static CheckerProgramPointTag Tag(this, "NilReceiver");

  // Check the return type of the message expression.  A message to nil will
  // return different values depending on the return type and the architecture.
  QualType RetTy = Msg.getResultType();
  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
  const LocationContext *LCtx = C.getLocationContext();

  if (CanRetTy->isStructureOrClassType()) {
    // Structure returns are safe since the compiler zeroes them out.
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    return;
  }

  // Other cases: check if sizeof(return type) > sizeof(void*)
  if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
                                  .isConsumedExpr(Msg.getOriginExpr())) {
    // Compute: sizeof(void *) and sizeof(return type)
    const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
    const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);

    if (CanRetTy.getTypePtr()->isReferenceType()||
        (voidPtrSize < returnTypeSize &&
         !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
           (Ctx.FloatTy == CanRetTy ||
            Ctx.DoubleTy == CanRetTy ||
            Ctx.LongDoubleTy == CanRetTy ||
            Ctx.LongLongTy == CanRetTy ||
            Ctx.UnsignedLongLongTy == CanRetTy)))) {
      if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag))
        emitNilReceiverBug(C, Msg, N);
      return;
    }

    // Handle the safe cases where the return value is 0 if the
    // receiver is nil.
    //
    // FIXME: For now take the conservative approach that we only
    // return null values if we *know* that the receiver is nil.
    // This is because we can have surprises like:
    //
    //   ... = [[NSScreens screens] objectAtIndex:0];
    //
    // What can happen is that [... screens] could return nil, but
    // it most likely isn't nil.  We should assume the semantics
    // of this case unless we have *a lot* more knowledge.
    //
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    return;
  }

  C.addTransition(state);
}
void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
        const Stmt *StoreE,
        CheckerContext &C) const {
    if (!val.isUndef())
        return;

    // Do not report assignments of uninitialized values inside swap functions.
    // This should allow to swap partially uninitialized structs
    // (radar://14129997)
    if (const FunctionDecl *EnclosingFunctionDecl =
                dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
        if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
            return;

    ExplodedNode *N = C.generateSink();

    if (!N)
        return;

    const char *str = "Assigned value is garbage or undefined";

    if (!BT)
        BT.reset(new BuiltinBug(str));

    // Generate a report for this bug.
    const Expr *ex = 0;

    while (StoreE) {
        if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
            if (B->isCompoundAssignmentOp()) {
                ProgramStateRef state = C.getState();
                if (state->getSVal(B->getLHS(), C.getLocationContext()).isUndef()) {
                    str = "The left expression of the compound assignment is an "
                          "uninitialized value. The computed value will also be garbage";
                    ex = B->getLHS();
                    break;
                }
            }

            ex = B->getRHS();
            break;
        }

        if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
            const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
            ex = VD->getInit();
        }

        break;
    }

    BugReport *R = new BugReport(*BT, str, N);
    if (ex) {
        R->addRange(ex->getSourceRange());
        bugreporter::trackNullOrUndefValue(N, ex, *R);
    }
    C.emitReport(R);
}
Пример #15
0
void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                                CheckerContext &C) const {
  SVal recVal = msg.getReceiverSVal();
  if (recVal.isUndef()) {
    if (ExplodedNode *N = C.generateSink()) {
      BugType *BT = 0;
      switch (msg.getMessageKind()) {
      case OCM_Message:
        if (!BT_msg_undef)
          BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
                                            "is an uninitialized value"));
        BT = BT_msg_undef.get();
        break;
      case OCM_PropertyAccess:
        if (!BT_objc_prop_undef)
          BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
                                                  "uninitialized object "
                                                  "pointer"));
        BT = BT_objc_prop_undef.get();
        break;
      case OCM_Subscript:
        if (!BT_objc_subscript_undef)
          BT_objc_subscript_undef.reset(new BuiltinBug("Subscript access on an "
                                                       "uninitialized object "
                                                       "pointer"));
        BT = BT_objc_subscript_undef.get();
        break;
      }
      assert(BT && "Unknown message kind.");

      BugReport *R = new BugReport(*BT, BT->getName(), N);
      const ObjCMessageExpr *ME = msg.getOriginExpr();
      R->addRange(ME->getReceiverRange());

      // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
      if (const Expr *ReceiverE = ME->getInstanceReceiver())
        R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
                                                                   ReceiverE,
                                                                   R));
      C.EmitReport(R);
    }
    return;
  } else {
    // Bifurcate the state into nil and non-nil ones.
    DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);

    ProgramStateRef state = C.getState();
    ProgramStateRef notNilState, nilState;
    llvm::tie(notNilState, nilState) = state->assume(receiverVal);

    // Handle receiver must be nil.
    if (nilState && !notNilState) {
      HandleNilReceiver(C, state, msg);
      return;
    }
  }
}
Пример #16
0
void ArrayBoundChecker::checkLocation(SVal l, bool isLoad,
                                      CheckerContext &C) const {
  // Check for out of bound array element access.
  const MemRegion *R = l.getAsRegion();
  if (!R)
    return;

  const ElementRegion *ER = dyn_cast<ElementRegion>(R);
  if (!ER)
    return;

  // Get the index of the accessed element.
  DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());

  // Zero index is always in bound, this also passes ElementRegions created for
  // pointer casts.
  if (Idx.isZeroConstant())
    return;

  const GRState *state = C.getState();

  // Get the size of the array.
  DefinedOrUnknownSVal NumElements 
    = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), 
                                            ER->getValueType());

  const GRState *StInBound = state->assumeInBound(Idx, NumElements, true);
  const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false);
  if (StOutBound && !StInBound) {
    ExplodedNode *N = C.generateSink(StOutBound);
    if (!N)
      return;
  
    if (!BT)
      BT.reset(new BuiltinBug("Out-of-bound array access",
                       "Access out-of-bound array element (buffer overflow)"));

    // FIXME: It would be nice to eventually make this diagnostic more clear,
    // e.g., by referencing the original declaration or by saying *why* this
    // reference is outside the range.

    // Generate a report for this bug.
    RangedBugReport *report = 
      new RangedBugReport(*BT, BT->getDescription(), N);

    report->addRange(C.getStmt()->getSourceRange());
    C.EmitReport(report);
    return;
  }
  
  // Array bound check succeeded.  From this point forward the array bound
  // should always succeed.
  assert(StInBound);
  C.addTransition(StInBound);
}
Пример #17
0
void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
                                                CheckerContext &C) const {

  ProgramStateRef state = C.getState();
  const LocationContext *LCtx = C.getLocationContext();

  // FIXME: Handle 'super'?
  if (const Expr *receiver = msg.getInstanceReceiver()) {
    SVal recVal = state->getSVal(receiver, LCtx);
    if (recVal.isUndef()) {
      if (ExplodedNode *N = C.generateSink()) {
        BugType *BT = 0;
        if (msg.isPureMessageExpr()) {
          if (!BT_msg_undef)
            BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
                                              "is an uninitialized value"));
          BT = BT_msg_undef.get();
        }
        else {
          if (!BT_objc_prop_undef)
            BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
                                              "uninitialized object pointer"));
          BT = BT_objc_prop_undef.get();
        }
        BugReport *R =
          new BugReport(*BT, BT->getName(), N);
        R->addRange(receiver->getSourceRange());
        R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
                                                                   receiver,
                                                                   R));
        C.EmitReport(R);
      }
      return;
    } else {
      // Bifurcate the state into nil and non-nil ones.
      DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
  
      ProgramStateRef notNilState, nilState;
      llvm::tie(notNilState, nilState) = state->assume(receiverVal);
  
      // Handle receiver must be nil.
      if (nilState && !notNilState) {
        HandleNilReceiver(C, state, msg);
        return;
      }
    }
  }

  const char *bugDesc = msg.isPropertySetter() ?
                     "Argument for property setter is an uninitialized value"
                   : "Argument in message expression is an uninitialized value";
  // Check for any arguments that are uninitialized/undefined.
  PreVisitProcessArgs(C, CallOrObjCMessage(msg, state, LCtx),
                      bugDesc, BT_msg_arg);
}
Пример #18
0
void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
                                        const CallExpr *CE) {
  ExplodedNode *N = C.generateSink();
  if (!N)
    return;

  BugReport *R = new BugReport(*BT, BT->getName(), N);
  R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
                               bugreporter::GetCalleeExpr(N)));
  C.EmitReport(R);
}
Пример #19
0
void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
                                             CheckerContext &C) const {
  ProgramStateRef state = C.getState();

  const Expr *RetE = RS->getRetValue();
  if (!RetE)
    return;

  SVal V = state->getSVal(RetE, C.getLocationContext());
  const MemRegion *R = V.getAsRegion();

  const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R);
  if (!ER)
    return;

  DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
  // Zero index is always in bound, this also passes ElementRegions created for
  // pointer casts.
  if (Idx.isZeroConstant())
    return;
  // FIXME: All of this out-of-bounds checking should eventually be refactored
  // into a common place.

  DefinedOrUnknownSVal NumElements
    = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
                                           ER->getValueType());

  ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
  ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false);
  if (StOutBound && !StInBound) {
    ExplodedNode *N = C.generateSink(StOutBound);

    if (!N)
      return;

    // FIXME: This bug correspond to CWE-466.  Eventually we should have bug
    // types explicitly reference such exploit categories (when applicable).
    if (!BT)
      BT.reset(new BuiltinBug(
          this, "Return of pointer value outside of expected range",
          "Returned pointer value points outside the original object "
          "(potential buffer overflow)"));

    // FIXME: It would be nice to eventually make this diagnostic more clear,
    // e.g., by referencing the original declaration or by saying *why* this
    // reference is outside the range.

    // Generate a report for this bug.
    auto report = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N);

    report->addRange(RetE->getSourceRange());
    C.emitReport(std::move(report));
  }
}
void NilArgChecker::WarnIfNilArg(CheckerContext &C,
                                 const ObjCMethodCall &msg,
                                 unsigned int Arg,
                                 FoundationClass Class,
                                 bool CanBeSubscript) const {
  // Check if the argument is nil.
  ProgramStateRef State = C.getState();
  if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
      return;
      
  if (!BT)
    BT.reset(new APIMisuse("nil argument"));

  if (ExplodedNode *N = C.generateSink()) {
    SmallString<128> sbuf;
    llvm::raw_svector_ostream os(sbuf);

    if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {

      if (Class == FC_NSArray) {
        os << "Array element cannot be nil";
      } else if (Class == FC_NSDictionary) {
        if (Arg == 0) {
          os << "Value stored into '";
          os << GetReceiverInterfaceName(msg) << "' cannot be nil";
        } else {
          assert(Arg == 1);
          os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
        }
      } else
        llvm_unreachable("Missing foundation class for the subscript expr");

    } else {
      if (Class == FC_NSDictionary) {
        if (Arg == 0)
          os << "Value argument ";
        else {
          assert(Arg == 1);
          os << "Key argument ";
        }
        os << "to '" << msg.getSelector().getAsString() << "' cannot be nil";
      } else {
        os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
        << msg.getSelector().getAsString() << "' cannot be nil";
      }
    }

    BugReport *R = new BugReport(*BT, os.str(), N);
    R->addRange(msg.getArgSourceRange(Arg));
    bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R);
    C.emitReport(R);
  }
}
void NilArgChecker::warnIfNilExpr(const Expr *E,
                                  const char *Msg,
                                  CheckerContext &C) const {
    ProgramStateRef State = C.getState();
    if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {

        if (ExplodedNode *N = C.generateSink()) {
            generateBugReport(N, Msg, E->getSourceRange(), E, C);
        }

    }
}
Пример #22
0
void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
  const Expr *E = CE->getSubExpr();
  ASTContext &Ctx = C.getASTContext();
  QualType ToTy = Ctx.getCanonicalType(CE->getType());
  const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());

  if (!ToPTy)
    return;

  QualType ToPointeeTy = ToPTy->getPointeeType();

  // Only perform the check if 'ToPointeeTy' is a complete type.
  if (ToPointeeTy->isIncompleteType())
    return;

  ProgramStateRef state = C.getState();
  const MemRegion *R = state->getSVal(E, C.getLocationContext()).getAsRegion();
  if (R == 0)
    return;

  const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
  if (SR == 0)
    return;

  SValBuilder &svalBuilder = C.getSValBuilder();
  SVal extent = SR->getExtent(svalBuilder);
  const llvm::APSInt *extentInt = svalBuilder.getKnownValue(state, extent);
  if (!extentInt)
    return;

  CharUnits regionSize = CharUnits::fromQuantity(extentInt->getSExtValue());
  CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy);

  // Ignore void, and a few other un-sizeable types.
  if (typeSize.isZero())
    return;

  if (regionSize % typeSize == 0)
    return;

  if (evenFlexibleArraySize(Ctx, regionSize, typeSize, ToPointeeTy))
    return;

  if (ExplodedNode *errorNode = C.generateSink()) {
    if (!BT)
      BT.reset(new BuiltinBug(this, "Cast region with wrong size.",
                                    "Cast a region whose size is not a multiple"
                                    " of the destination type size."));
    BugReport *R = new BugReport(*BT, BT->getDescription(), errorNode);
    R->addRange(CE->getSourceRange());
    C.emitReport(R);
  }
}
Пример #23
0
void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
                                   CheckerContext &C) const {
  // If we're binding to a reference, check if the value is known to be null.
  if (V.isUndef())
    return;

  const MemRegion *MR = L.getAsRegion();
  const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR);
  if (!TVR)
    return;

  if (!TVR->getValueType()->isReferenceType())
    return;

  ProgramStateRef State = C.getState();

  ProgramStateRef StNonNull, StNull;
  llvm::tie(StNonNull, StNull) =
      State->assume(V.castAs<DefinedOrUnknownSVal>());

  if (StNull) {
    if (!StNonNull) {
      reportBug(StNull, S, C, /*isBind=*/true);
      return;
    }

    // At this point the value could be either null or non-null.
    // Record this as an "implicit" null dereference.
    if (ExplodedNode *N = C.generateSink(StNull)) {
      ImplicitNullDerefEvent event = { V, /*isLoad=*/true, N,
                                       &C.getBugReporter() };
      dispatchEvent(event);
    }
  }

  // Unlike a regular null dereference, initializing a reference with a
  // dereferenced null pointer does not actually cause a runtime exception in
  // Clang's implementation of references.
  //
  //   int &r = *p; // safe??
  //   if (p != NULL) return; // uh-oh
  //   r = 5; // trap here
  //
  // The standard says this is invalid as soon as we try to create a "null
  // reference" (there is no such thing), but turning this into an assumption
  // that 'p' is never null will not match our actual runtime behavior.
  // So we do not record this assumption, allowing us to warn on the last line
  // of this example.
  //
  // We do need to add a transition because we may have generated a sink for
  // the "implicit" null dereference.
  C.addTransition(State, this);
}
void DivZeroChecker::reportBug(const char *Msg,
                               ProgramStateRef StateZero,
                               CheckerContext &C) const {
  if (ExplodedNode *N = C.generateSink(StateZero)) {
    if (!BT)
      BT.reset(new BuiltinBug("Division by zero"));

    BugReport *R = new BugReport(*BT, Msg, N);
    bugreporter::trackNullOrUndefValue(N, bugreporter::GetDenomExpr(N), *R);
    C.emitReport(R);
  }
}
Пример #25
0
void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
                                         const ObjCAtSynchronizedStmt *S) {

  const Expr *Ex = S->getSynchExpr();
  const GRState *state = C.getState();
  SVal V = state->getSVal(Ex);

  // Uninitialized value used for the mutex?
  if (isa<UndefinedVal>(V)) {
    if (ExplodedNode *N = C.generateSink()) {
      if (!BT_undef)
        BT_undef = new BuiltinBug("Uninitialized value used as mutex "
                                  "for @synchronized");
      EnhancedBugReport *report =
        new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
      C.EmitReport(report);
    }
    return;
  }

  if (V.isUnknown())
    return;

  // Check for null mutexes.
  const GRState *notNullState, *nullState;
  llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V));

  if (nullState) {
    if (!notNullState) {
      // Generate an error node.  This isn't a sink since
      // a null mutex just means no synchronization occurs.
      if (ExplodedNode *N = C.generateNode(nullState)) {
        if (!BT_null)
          BT_null = new BuiltinBug("Nil value used as mutex for @synchronized() "
                                   "(no synchronization will occur)");
        EnhancedBugReport *report =
          new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
        report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
                                  Ex);

        C.EmitReport(report);
        return;
      }
    }
    // Don't add a transition for 'nullState'.  If the value is
    // under-constrained to be null or non-null, assume it is non-null
    // afterwards.
  }

  if (notNullState)
    C.addTransition(notNullState);
}
Пример #26
0
void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
                                     CheckerContext &C) const {

  const Expr *Ex = S->getSynchExpr();
  ProgramStateRef state = C.getState();
  SVal V = state->getSVal(Ex, C.getLocationContext());

  // Uninitialized value used for the mutex?
  if (V.getAs<UndefinedVal>()) {
    if (ExplodedNode *N = C.generateSink()) {
      if (!BT_undef)
        BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex "
                                            "for @synchronized"));
      BugReport *report =
        new BugReport(*BT_undef, BT_undef->getDescription(), N);
      bugreporter::trackNullOrUndefValue(N, Ex, *report);
      C.emitReport(report);
    }
    return;
  }

  if (V.isUnknown())
    return;

  // Check for null mutexes.
  ProgramStateRef notNullState, nullState;
  llvm::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>());

  if (nullState) {
    if (!notNullState) {
      // Generate an error node.  This isn't a sink since
      // a null mutex just means no synchronization occurs.
      if (ExplodedNode *N = C.addTransition(nullState)) {
        if (!BT_null)
          BT_null.reset(new BuiltinBug(
              this, "Nil value used as mutex for @synchronized() "
                    "(no synchronization will occur)"));
        BugReport *report =
          new BugReport(*BT_null, BT_null->getDescription(), N);
        bugreporter::trackNullOrUndefValue(N, Ex, *report);

        C.emitReport(report);
        return;
      }
    }
    // Don't add a transition for 'nullState'.  If the value is
    // under-constrained to be null or non-null, assume it is non-null
    // afterwards.
  }

  if (notNullState)
    C.addTransition(notNullState);
}
Пример #27
0
static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
                    const Expr *TrackingE = 0) {
  ExplodedNode *N = C.generateSink();
  if (!N)
    return;

  BugReport *Report = new BugReport(BT, BT.getDescription(), N);

  Report->addRange(RetE->getSourceRange());
  bugreporter::trackNullOrUndefValue(N, TrackingE ? TrackingE : RetE, *Report);

  C.emitReport(Report);
}
Пример #28
0
static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
                    const Expr *TrackingE = nullptr) {
  ExplodedNode *N = C.generateSink();
  if (!N)
    return;

  auto Report = llvm::make_unique<BugReport>(BT, BT.getDescription(), N);

  Report->addRange(RetE->getSourceRange());
  bugreporter::trackNullOrUndefValue(N, TrackingE ? TrackingE : RetE, *Report);

  C.emitReport(std::move(Report));
}
Пример #29
0
void PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C,
                                               const CallExpr *CE) const {
  if (!BT_destroylock)
    BT_destroylock.reset(new BugType(this, "Use destroyed lock",
                                     "Lock checker"));
  ExplodedNode *N = C.generateSink();
  if (!N)
    return;
  auto Report = llvm::make_unique<BugReport>(
      *BT_destroylock, "This lock has already been destroyed", N);
  Report->addRange(CE->getArg(0)->getSourceRange());
  C.emitReport(std::move(Report));
}
Пример #30
0
void UnixAPIChecker::ReportOpenBug(CheckerContext &C,
                                   ProgramStateRef State,
                                   const char *Msg,
                                   SourceRange SR) const {
  ExplodedNode *N = C.generateSink(State);
  if (!N)
    return;

  LazyInitialize(BT_open, "Improper use of 'open'");

  auto Report = llvm::make_unique<BugReport>(*BT_open, Msg, N);
  Report->addRange(SR);
  C.emitReport(std::move(Report));
}