Optional<DefinedOrUnknownSVal>
IntegerOverflowChecker::checkSub(CheckerContext &C, const SVal &Lhs,
                                 const SVal &Rhs, const QualType &BinType,
                                 bool &isOverflow) const {
  SVal CondOverflow;
  ProgramStateRef State = C.getState();
  SValBuilder &SvalBuilder = C.getSValBuilder();
  SVal NullSval = SvalBuilder.makeZeroVal(BinType);
  QualType CondType = SvalBuilder.getConditionType();
  SVal ValArgSub = SvalBuilder.evalBinOp(State, BO_Sub, Lhs, Rhs, BinType);
  if (BinType->isSignedIntegerType()) {
    // When first operand is negative
    // lhs < 0
    SVal CondLhsLtNull = SvalBuilder.evalBinOp(State, BO_LT, Lhs, NullSval,
                                               CondType);
    // rhs > 0
    SVal CondRhsGtNull = SvalBuilder.evalBinOp(State, BO_GT, Rhs, NullSval,
                                               CondType);
    // rhs > 0 && lhs < 0
    SVal CondLhsLtNullRhsGtNull =
        SvalBuilder.evalBinOp(State, BO_And, CondLhsLtNull, CondRhsGtNull,
                              CondType);
    // lhs - rhs >= 0
    SVal CondArgSubGeNull = SvalBuilder.evalBinOp(State, BO_GE, ValArgSub,
                                                  NullSval, CondType);

    // rhs > 0 && lhs < 0 && lhs-rhs >= 0
    SVal CondNegativeOverflow =
        SvalBuilder.evalBinOp(State, BO_And, CondLhsLtNullRhsGtNull,
                              CondArgSubGeNull, CondType);

    // When first operand is positive
    // lhs > 0
    SVal CondLhsGtNull = SvalBuilder.evalBinOp(State, BO_GT, Lhs, NullSval,
                                               CondType);
    // rhs < 0
    SVal CondRhsLtNull = SvalBuilder.evalBinOp(State, BO_LT, Rhs, NullSval,
                                               CondType);
    // rhs < 0 && lhs > 0
    SVal CondLhsGtNullRhsLtNull =
        SvalBuilder.evalBinOp(State, BO_And, CondLhsGtNull, CondRhsLtNull,
                              CondType);
    // lhs - rhs <= 0
    SVal CondArgSubLeNull = SvalBuilder.evalBinOp(State, BO_LE, ValArgSub,
                                                  NullSval, CondType);

    // rhs < 0 && lhs > 0 && lhs - rhs <= 0
    SVal CondPositiveOverflow =
        SvalBuilder.evalBinOp(State, BO_And, CondLhsGtNullRhsLtNull,
                              CondArgSubLeNull, CondType);

    CondOverflow = SvalBuilder.evalBinOp(State, BO_Or, CondNegativeOverflow,
                                         CondPositiveOverflow, CondType);
    if (!CondPositiveOverflow.isZeroConstant())
      isOverflow = true;
  } else
    CondOverflow = SvalBuilder.evalBinOp(State, BO_LT, Lhs, Rhs, CondType);

  return CondOverflow.getAs<DefinedOrUnknownSVal>();
}
Beispiel #2
0
/// Returns NULL state if the collection is known to contain elements
/// (or is known not to contain elements if the Assumption parameter is false.)
static ProgramStateRef assumeCollectionNonEmpty(CheckerContext &C,
                                            ProgramStateRef State,
                                            const ObjCForCollectionStmt *FCS,
                                            bool Assumption = false) {
  if (!State)
    return NULL;

  SymbolRef CollectionS = C.getSVal(FCS->getCollection()).getAsSymbol();
  if (!CollectionS)
    return State;
  const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
  if (!CountS)
    return State;

  SValBuilder &SvalBuilder = C.getSValBuilder();
  SVal CountGreaterThanZeroVal =
    SvalBuilder.evalBinOp(State, BO_GT,
                          nonloc::SymbolVal(*CountS),
                          SvalBuilder.makeIntVal(0, (*CountS)->getType()),
                          SvalBuilder.getConditionType());
  Optional<DefinedSVal> CountGreaterThanZero =
    CountGreaterThanZeroVal.getAs<DefinedSVal>();
  if (!CountGreaterThanZero) {
    // The SValBuilder cannot construct a valid SVal for this condition.
    // This means we cannot properly reason about it.
    return State;
  }

  return State->assume(*CountGreaterThanZero, Assumption);
}
Beispiel #3
0
void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
    const GRState *state = C.getState();
    unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
    SValBuilder &svalBuilder = C.getSValBuilder();
    DefinedSVal RetVal =
        cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, Count));
    state = state->BindExpr(CE, RetVal);

    ConstraintManager &CM = C.getConstraintManager();
    // Bifurcate the state into two: one with a valid FILE* pointer, the other
    // with a NULL.
    const GRState *stateNotNull, *stateNull;
    llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);

    if (SymbolRef Sym = RetVal.getAsSymbol()) {
        // if RetVal is not NULL, set the symbol's state to Opened.
        stateNotNull =
            stateNotNull->set<StreamState>(Sym,StreamState::getOpened(CE));
        stateNull =
            stateNull->set<StreamState>(Sym, StreamState::getOpenFailed(CE));

        C.addTransition(stateNotNull);
        C.addTransition(stateNull);
    }
}
Beispiel #4
0
void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
  ProgramStateRef state = C.getState();
  SValBuilder &svalBuilder = C.getSValBuilder();
  const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
  DefinedSVal RetVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx,
                                                    C.blockCount())
      .castAs<DefinedSVal>();
  state = state->BindExpr(CE, C.getLocationContext(), RetVal);

  ConstraintManager &CM = C.getConstraintManager();
  // Bifurcate the state into two: one with a valid FILE* pointer, the other
  // with a NULL.
  ProgramStateRef stateNotNull, stateNull;
  std::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);

  if (SymbolRef Sym = RetVal.getAsSymbol()) {
    // if RetVal is not NULL, set the symbol's state to Opened.
    stateNotNull =
      stateNotNull->set<StreamMap>(Sym,StreamState::getOpened(CE));
    stateNull =
      stateNull->set<StreamMap>(Sym, StreamState::getOpenFailed(CE));

    C.addTransition(stateNotNull);
    C.addTransition(stateNull);
  }
}
/// Returns NULL state if the collection is known to contain elements
/// (or is known not to contain elements if the Assumption parameter is false.)
static ProgramStateRef
assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
                         SymbolRef CollectionS, bool Assumption) {
  if (!State || !CollectionS)
    return State;

  const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
  if (!CountS) {
    const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
    if (!KnownNonEmpty)
      return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
    return (Assumption == *KnownNonEmpty) ? State : nullptr;
  }

  SValBuilder &SvalBuilder = C.getSValBuilder();
  SVal CountGreaterThanZeroVal =
    SvalBuilder.evalBinOp(State, BO_GT,
                          nonloc::SymbolVal(*CountS),
                          SvalBuilder.makeIntVal(0, (*CountS)->getType()),
                          SvalBuilder.getConditionType());
  Optional<DefinedSVal> CountGreaterThanZero =
    CountGreaterThanZeroVal.getAs<DefinedSVal>();
  if (!CountGreaterThanZero) {
    // The SValBuilder cannot construct a valid SVal for this condition.
    // This means we cannot properly reason about it.
    return State;
  }

  return State->assume(*CountGreaterThanZero, Assumption);
}
void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE,
                                               CheckerContext &C) const {
  
  // Get the result type of the call.
  QualType expectedResultTy = CE->getType();

  // Fetch the signature of the called function.
  const ProgramState *state = C.getState();
  const LocationContext *LCtx = C.getLocationContext();

  SVal V = state->getSVal(CE, LCtx);
  
  if (V.isUnknown())
    return;
  
  // Casting to void?  Discard the value.
  if (expectedResultTy->isVoidType()) {
    C.addTransition(state->BindExpr(CE, LCtx, UnknownVal()));
    return;
  }                   

  const MemRegion *callee = state->getSVal(CE->getCallee(), LCtx).getAsRegion();
  if (!callee)
    return;

  QualType actualResultTy;
  
  if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) {
    const FunctionDecl *FD = FT->getDecl();
    actualResultTy = FD->getResultType();
  }
  else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) {
    const BlockTextRegion *BR = BD->getCodeRegion();
    const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>();
    const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
    actualResultTy = FT->getResultType();
  }

  // Can this happen?
  if (actualResultTy.isNull())
    return;

  // For now, ignore references.
  if (actualResultTy->getAs<ReferenceType>())
    return;
  

  // Are they the same?
  if (expectedResultTy != actualResultTy) {
    // FIXME: Do more checking and actual emit an error. At least performing
    // the cast avoids some assertion failures elsewhere.
    SValBuilder &svalBuilder = C.getSValBuilder();
    V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy);
    C.addTransition(state->BindExpr(CE, LCtx, V));
  }
}
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)
    return;

  const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
  if (!SR)
    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.generateErrorNode()) {
    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."));
    auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), errorNode);
    R->addRange(CE->getSourceRange());
    C.emitReport(std::move(R));
  }
}
Beispiel #8
0
void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) {
  const GRState *state = C.getState();
  SValBuilder &svalBuilder = C.getSValBuilder();

  SVal count = state->getSVal(CE->getArg(0));
  SVal elementSize = state->getSVal(CE->getArg(1));
  SVal TotalSize = svalBuilder.evalBinOp(state, BO_Mul, count, elementSize,
                                        svalBuilder.getContext().getSizeType());  
  SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);

  C.addTransition(MallocMemAux(C, CE, TotalSize, zeroVal, state));
}
static Optional<nonloc::LazyCompoundVal>
getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context) {

  Loc ThisLoc = Context.getSValBuilder().getCXXThis(CtorDecl->getParent(),
                                                    Context.getStackFrame());
  // Getting the value for 'this'.
  SVal This = Context.getState()->getSVal(ThisLoc);

  // Getting the value for '*this'.
  SVal Object = Context.getState()->getSVal(This.castAs<Loc>());

  return Object.getAs<nonloc::LazyCompoundVal>();
}
Optional<DefinedOrUnknownSVal>
IntegerOverflowChecker::checkMul(CheckerContext &C, const SVal &Lhs,
                                 const SVal &Rhs, const QualType &BinType,
                                 bool &isOverflow) const {
  ProgramStateRef State = C.getState();
  ProgramStateRef CondNotOverflow, CondPossibleOverflow;
  SValBuilder &SvalBuilder = C.getSValBuilder();
  SVal NullSval = SvalBuilder.makeZeroVal(BinType);
  QualType CondType = SvalBuilder.getConditionType();

  // lhs == 0
  SVal LhsNotNull = SvalBuilder.evalBinOp(State, BO_NE, Lhs, NullSval,
                                          CondType);

  // rhs == 0
  SVal RhsNotNull = SvalBuilder.evalBinOp(State, BO_NE, Rhs, NullSval,
                                          CondType);

  Optional<DefinedOrUnknownSVal> CondOverflow =
      SvalBuilder.evalBinOp(State, BO_And, LhsNotNull, RhsNotNull, CondType)
          .getAs<DefinedOrUnknownSVal>();

  if (!CondOverflow.hasValue())
    return CondOverflow;

  std::tie(CondPossibleOverflow, CondNotOverflow) =
      State->assume(*CondOverflow);

  if (CondNotOverflow && CondPossibleOverflow)
    return CondOverflow;

  if (CondPossibleOverflow) {
    // lhs * rhs
    SVal ValMulti = SvalBuilder.evalBinOp(State, BO_Mul, Lhs, Rhs, BinType);
    // First operand(lhs) is not 0
    // (lhs * rhs)/lhs
    SVal ValDiv = SvalBuilder.evalBinOp(State, BO_Div, ValMulti, Lhs, BinType);
    // (lhs * rhs)/lhs != rhs

    CondOverflow = SvalBuilder.evalBinOp(State, BO_NE, ValDiv, Rhs, CondType)
                       .getAs<DefinedOrUnknownSVal>();
  }

  isOverflow = BinType->isUnsignedIntegerOrEnumerationType() ||
               SvalBuilder.evalBinOp(State, BO_LT, Lhs, NullSval, CondType)
                       .isZeroConstant() ==
                   SvalBuilder.evalBinOp(State, BO_LT, Rhs, NullSval, CondType)
                       .isZeroConstant();

  return CondOverflow;
}
void
UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
                                            CheckerContext &C) const {
  if (!BE->getBlockDecl()->hasCaptures())
    return;

  ProgramStateRef state = C.getState();
  const BlockDataRegion *R =
    cast<BlockDataRegion>(state->getSVal(BE,
                                         C.getLocationContext()).getAsRegion());

  BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
                                            E = R->referenced_vars_end();

  for (; I != E; ++I) {
    // This VarRegion is the region associated with the block; we need
    // the one associated with the encompassing context.
    const VarRegion *VR = *I;
    const VarDecl *VD = VR->getDecl();

    if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
      continue;

    // Get the VarRegion associated with VD in the local stack frame.
    const LocationContext *LC = C.getLocationContext();
    VR = C.getSValBuilder().getRegionManager().getVarRegion(VD, LC);
    SVal VRVal = state->getSVal(VR);

    if (VRVal.isUndef())
      if (ExplodedNode *N = C.generateSink()) {
        if (!BT)
          BT.reset(new BuiltinBug("uninitialized variable captured by block"));

        // Generate a bug report.
        SmallString<128> buf;
        llvm::raw_svector_ostream os(buf);

        os << "Variable '" << VD->getName() 
           << "' is uninitialized when captured by block";

        BugReport *R = new BugReport(*BT, os.str(), N);
        if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
          R->addRange(Ex->getSourceRange());
        R->addVisitor(new FindLastStoreBRVisitor(VRVal, VR));
        // need location of block
        C.EmitReport(R);
      }
  }
}
bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
                                      CheckerContext &C) const {
  ProgramStateRef state = C.getState();
  const FunctionDecl *FD = C.getCalleeDecl(CE);
  const LocationContext *LCtx = C.getLocationContext();
  if (!FD)
    return false;

  unsigned id = FD->getBuiltinID();

  if (!id)
    return false;

  switch (id) {
  case Builtin::BI__builtin_expect: {
    // For __builtin_expect, just return the value of the subexpression.
    assert (CE->arg_begin() != CE->arg_end());
    SVal X = state->getSVal(*(CE->arg_begin()), LCtx);
    C.addTransition(state->BindExpr(CE, LCtx, X));
    return true;
  }

  case Builtin::BI__builtin_alloca: {
    // FIXME: Refactor into StoreManager itself?
    MemRegionManager& RM = C.getStoreManager().getRegionManager();
    const AllocaRegion* R =
      RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());

    // Set the extent of the region in bytes. This enables us to use the
    // SVal of the argument directly. If we save the extent in bits, we
    // cannot represent values like symbol*8.
    DefinedOrUnknownSVal Size =
        state->getSVal(*(CE->arg_begin()), LCtx).castAs<DefinedOrUnknownSVal>();

    SValBuilder& svalBuilder = C.getSValBuilder();
    DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
    DefinedOrUnknownSVal extentMatchesSizeArg =
      svalBuilder.evalEQ(state, Extent, Size);
    state = state->assume(extentMatchesSizeArg, true);
    assert(state && "The region should not have any previous constraints");

    C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
    return true;
  }
  }

  return false;
}
void IntegerOverflowChecker::checkPostStmt(const CXXNewExpr *NewExpr,
                                           CheckerContext &C) const {
  if (!Filter.CheckIntegerOverflowDef)
    return;

  if (NewExpr->getOperatorNew()->getOverloadedOperator() != OO_Array_New)
    return;

  const Expr *ArrSize = NewExpr->getArraySize();
  SVal ElementCount = C.getSVal(ArrSize);
  ProgramStateRef State = C.getState();

  if (makeGlobalsMembersHeuristics(ElementCount, ArrSize, C)) {
    C.addTransition(addToWhiteList(ElementCount, State));
    return;
  }

  QualType NewExprType = NewExpr->getAllocatedType();
  uint64_t NewExprTypeSize = C.getASTContext().getTypeSizeInChars(NewExprType)
                                              .getQuantity();
  SValBuilder &SvalBuilder = C.getSValBuilder();
  SVal NewExprTypeSizeVal = SvalBuilder.makeIntVal(NewExprTypeSize, true);

  bool isOverflow;
  Optional<DefinedOrUnknownSVal> CondOverflow = checkMul(C, NewExprTypeSizeVal,
                                                         ElementCount,
                                                         ArrSize->getType(),
                                                         isOverflow);

  if (!CondOverflow)
    return;

  ProgramStateRef StateOverflow, StateNotOverflow;
  std::tie(StateOverflow, StateNotOverflow) = State->assume(*CondOverflow);

  if (!StateOverflow || (StateNotOverflow && !State->isTainted(ElementCount)))
    return;

  std::string Msg = composeMsg(StateNotOverflow, NewExprTypeSizeVal,
                               ElementCount, 0, ArrSize, false, isOverflow, 0,
                               C);

  reportBug(Msg, C, NewExpr->getExprLoc(), false);
}
Beispiel #14
0
/// Constrain the passed-in state to assume two values are equal.
ProgramStateRef GTestChecker::assumeValuesEqual(SVal Val1, SVal Val2,
                                                ProgramStateRef State,
                                                CheckerContext &C) {
  if (!Val1.getAs<DefinedOrUnknownSVal>() ||
      !Val2.getAs<DefinedOrUnknownSVal>())
    return State;

  auto ValuesEqual =
      C.getSValBuilder().evalEQ(State, Val1.castAs<DefinedOrUnknownSVal>(),
                                Val2.castAs<DefinedOrUnknownSVal>());

  if (!ValuesEqual.getAs<DefinedSVal>())
    return State;

  State = C.getConstraintManager().assume(
      State, ValuesEqual.castAs<DefinedSVal>(), true);

  return State;
}
Beispiel #15
0
void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
                                               CheckerContext &C) const {
  ProgramStateRef State = C.getState();
  AllocatedDataTy ASet = State->get<AllocatedData>();
  if (ASet.isEmpty())
    return;

  bool Changed = false;
  AllocationPairVec Errors;
  for (AllocatedDataTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) {
    if (SR.isLive(I->first))
      continue;

    Changed = true;
    State = State->remove<AllocatedData>(I->first);
    // If the allocated symbol is null or if the allocation call might have
    // returned an error, do not report.
    ConstraintManager &CMgr = State->getConstraintManager();
    ConditionTruthVal AllocFailed = CMgr.isNull(State, I.getKey());
    if (AllocFailed.isConstrainedTrue() ||
        definitelyReturnedError(I->second.Region, State, C.getSValBuilder()))
      continue;
    Errors.push_back(std::make_pair(I->first, &I->second));
  }
  if (!Changed) {
    // Generate the new, cleaned up state.
    C.addTransition(State);
    return;
  }

  static SimpleProgramPointTag Tag("MacOSKeychainAPIChecker : DeadSymbolsLeak");
  ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);

  // Generate the error reports.
  for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
                                                       I != E; ++I) {
    C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
  }

  // Generate the new, cleaned up state.
  C.addTransition(State, N);
}
Beispiel #16
0
// TODO: Remove this after we ensure that checkDeadSymbols are always called.
void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &Ctx) const {
  const ProgramState *state = Ctx.getState();
  AllocatedSetTy AS = state->get<AllocatedData>();
  if (AS.isEmpty())
    return;

  // Anything which has been allocated but not freed (nor escaped) will be
  // found here, so report it.
  bool Changed = false;
  AllocationPairVec Errors;
  for (AllocatedSetTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) {
    Changed = true;
    state = state->remove<AllocatedData>(I->first);
    // If the allocated symbol is null or if error code was returned at
    // allocation, do not report.
    if (state->getSymVal(I.getKey()) ||
        definitelyReturnedError(I->second.Region, state,
                                Ctx.getSValBuilder())) {
      continue;
    }
    Errors.push_back(std::make_pair(I->first, &I->second));
  }

  // If no change, do not generate a new state.
  if (!Changed)
    return;

  ExplodedNode *N = Ctx.addTransition(state);
  if (!N)
    return;

  // Generate the error reports.
  for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
                                                       I != E; ++I) {
    Ctx.EmitReport(generateAllocatedDataNotReleasedReport(*I, N));
  }
}
Beispiel #17
0
void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
                                               CheckerContext &C) const {
  const ProgramState *State = C.getState();
  AllocatedSetTy ASet = State->get<AllocatedData>();
  if (ASet.isEmpty())
    return;

  bool Changed = false;
  AllocationPairVec Errors;
  for (AllocatedSetTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) {
    if (SR.isLive(I->first))
      continue;

    Changed = true;
    State = State->remove<AllocatedData>(I->first);
    // If the allocated symbol is null or if the allocation call might have
    // returned an error, do not report.
    if (State->getSymVal(I->first) ||
        definitelyReturnedError(I->second.Region, State, C.getSValBuilder()))
      continue;
    Errors.push_back(std::make_pair(I->first, &I->second));
  }
  if (!Changed)
    return;

  // Generate the new, cleaned up state.
  ExplodedNode *N = C.addTransition(State);
  if (!N)
    return;

  // Generate the error reports.
  for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
                                                       I != E; ++I) {
    C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N));
  }
}
Beispiel #18
0
void MPIChecker::allRegionsUsedByWait(
    llvm::SmallVector<const MemRegion *, 2> &ReqRegions,
    const MemRegion *const MR, const CallEvent &CE, CheckerContext &Ctx) const {

  MemRegionManager *const RegionManager = MR->getMemRegionManager();

  if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
    const MemRegion *SuperRegion{nullptr};
    if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {
      SuperRegion = ER->getSuperRegion();
    }

    // A single request is passed to MPI_Waitall.
    if (!SuperRegion) {
      ReqRegions.push_back(MR);
      return;
    }

    const auto &Size = Ctx.getStoreManager().getSizeInElements(
        Ctx.getState(), SuperRegion,
        CE.getArgExpr(1)->getType()->getPointeeType());
    const llvm::APSInt &ArrSize = Size.getAs<nonloc::ConcreteInt>()->getValue();

    for (size_t i = 0; i < ArrSize; ++i) {
      const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i);

      const ElementRegion *const ER = RegionManager->getElementRegion(
          CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion,
          Ctx.getASTContext());

      ReqRegions.push_back(ER->getAs<MemRegion>());
    }
  } else if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) {
    ReqRegions.push_back(MR);
  }
}
Beispiel #19
0
void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
  ProgramStateRef state = C.getState();

  if (CE->getNumArgs() < 2) {
    // The frontend should issue a warning for this case, so this is a sanity
    // check.
    return;
  } else if (CE->getNumArgs() == 3) {
    const Expr *Arg = CE->getArg(2);
    QualType QT = Arg->getType();
    if (!QT->isIntegerType()) {
      ReportOpenBug(C, state,
                    "Third argument to 'open' is not an integer",
                    Arg->getSourceRange());
      return;
    }
  } else if (CE->getNumArgs() > 3) {
    ReportOpenBug(C, state,
                  "Call to 'open' with more than three arguments",
                  CE->getArg(3)->getSourceRange());
    return;
  }

  // The definition of O_CREAT is platform specific.  We need a better way
  // of querying this information from the checking environment.
  if (!Val_O_CREAT.hasValue()) {
    if (C.getASTContext().getTargetInfo().getTriple().getVendor()
                                                      == llvm::Triple::Apple)
      Val_O_CREAT = 0x0200;
    else {
      // FIXME: We need a more general way of getting the O_CREAT value.
      // We could possibly grovel through the preprocessor state, but
      // that would require passing the Preprocessor object to the ExprEngine.
      // See also: MallocChecker.cpp / M_ZERO.
      return;
    }
  }

  // Now check if oflags has O_CREAT set.
  const Expr *oflagsEx = CE->getArg(1);
  const SVal V = state->getSVal(oflagsEx, C.getLocationContext());
  if (!V.getAs<NonLoc>()) {
    // The case where 'V' can be a location can only be due to a bad header,
    // so in this case bail out.
    return;
  }
  NonLoc oflags = V.castAs<NonLoc>();
  NonLoc ocreateFlag = C.getSValBuilder()
      .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
  SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
                                                      oflags, ocreateFlag,
                                                      oflagsEx->getType());
  if (maskedFlagsUC.isUnknownOrUndef())
    return;
  DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();

  // Check if maskedFlags is non-zero.
  ProgramStateRef trueState, falseState;
  std::tie(trueState, falseState) = state->assume(maskedFlags);

  // Only emit an error if the value of 'maskedFlags' is properly
  // constrained;
  if (!(trueState && !falseState))
    return;

  if (CE->getNumArgs() < 3) {
    ReportOpenBug(C, trueState,
                  "Call to 'open' requires a third argument when "
                  "the 'O_CREAT' flag is set",
                  oflagsEx->getSourceRange());
  }
}
Beispiel #20
0
void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
  // The definition of O_CREAT is platform specific.  We need a better way
  // of querying this information from the checking environment.
  if (!Val_O_CREAT.hasValue()) {
    if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
      Val_O_CREAT = 0x0200;
    else {
      // FIXME: We need a more general way of getting the O_CREAT value.
      // We could possibly grovel through the preprocessor state, but
      // that would require passing the Preprocessor object to the ExprEngine.
      return;
    }
  }

  // Look at the 'oflags' argument for the O_CREAT flag.
  const GRState *state = C.getState();

  if (CE->getNumArgs() < 2) {
    // The frontend should issue a warning for this case, so this is a sanity
    // check.
    return;
  }

  // Now check if oflags has O_CREAT set.
  const Expr *oflagsEx = CE->getArg(1);
  const SVal V = state->getSVal(oflagsEx);
  if (!isa<NonLoc>(V)) {
    // The case where 'V' can be a location can only be due to a bad header,
    // so in this case bail out.
    return;
  }
  NonLoc oflags = cast<NonLoc>(V);
  NonLoc ocreateFlag =
    cast<NonLoc>(C.getSValBuilder().makeIntVal(Val_O_CREAT.getValue(),
                                                oflagsEx->getType()));
  SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
                                                      oflags, ocreateFlag,
                                                      oflagsEx->getType());
  if (maskedFlagsUC.isUnknownOrUndef())
    return;
  DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC);

  // Check if maskedFlags is non-zero.
  const GRState *trueState, *falseState;
  llvm::tie(trueState, falseState) = state->assume(maskedFlags);

  // Only emit an error if the value of 'maskedFlags' is properly
  // constrained;
  if (!(trueState && !falseState))
    return;

  if (CE->getNumArgs() < 3) {
    ExplodedNode *N = C.generateSink(trueState);
    if (!N)
      return;

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

    RangedBugReport *report =
      new RangedBugReport(*BT_open,
                            "Call to 'open' requires a third argument when "
                            "the 'O_CREAT' flag is set", N);
    report->addRange(oflagsEx->getSourceRange());
    C.EmitReport(report);
  }
}
Beispiel #21
0
void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
                                           CheckerContext &C) const {
  unsigned idx = InvalidIdx;
  ProgramStateRef State = C.getState();

  const FunctionDecl *FD = C.getCalleeDecl(CE);
  if (!FD || FD->getKind() != Decl::Function)
    return;
  
  StringRef funName = C.getCalleeName(FD);
  if (funName.empty())
    return;

  // If it is a call to an allocator function, it could be a double allocation.
  idx = getTrackedFunctionIndex(funName, true);
  if (idx != InvalidIdx) {
    const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
    if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C))
      if (const AllocationState *AS = State->get<AllocatedData>(V)) {
        if (!definitelyReturnedError(AS->Region, State, C.getSValBuilder())) {
          // Remove the value from the state. The new symbol will be added for
          // tracking when the second allocator is processed in checkPostStmt().
          State = State->remove<AllocatedData>(V);
          ExplodedNode *N = C.addTransition(State);
          if (!N)
            return;
          initBugType();
          SmallString<128> sbuf;
          llvm::raw_svector_ostream os(sbuf);
          unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
          os << "Allocated data should be released before another call to "
              << "the allocator: missing a call to '"
              << FunctionsToTrack[DIdx].Name
              << "'.";
          BugReport *Report = new BugReport(*BT, os.str(), N);
          Report->addVisitor(new SecKeychainBugVisitor(V));
          Report->addRange(ArgExpr->getSourceRange());
          Report->markInteresting(AS->Region);
          C.emitReport(Report);
        }
      }
    return;
  }

  // Is it a call to one of deallocator functions?
  idx = getTrackedFunctionIndex(funName, false);
  if (idx == InvalidIdx)
    return;

  // Check the argument to the deallocator.
  const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
  SVal ArgSVal = State->getSVal(ArgExpr, C.getLocationContext());

  // Undef is reported by another checker.
  if (ArgSVal.isUndef())
    return;

  SymbolRef ArgSM = ArgSVal.getAsLocSymbol();

  // If the argument is coming from the heap, globals, or unknown, do not
  // report it.
  bool RegionArgIsBad = false;
  if (!ArgSM) {
    if (!isBadDeallocationArgument(ArgSVal.getAsRegion()))
      return;
    RegionArgIsBad = true;
  }

  // Is the argument to the call being tracked?
  const AllocationState *AS = State->get<AllocatedData>(ArgSM);
  if (!AS && FunctionsToTrack[idx].Kind != ValidAPI) {
    return;
  }
  // If trying to free data which has not been allocated yet, report as a bug.
  // TODO: We might want a more precise diagnostic for double free
  // (that would involve tracking all the freed symbols in the checker state).
  if (!AS || RegionArgIsBad) {
    // It is possible that this is a false positive - the argument might
    // have entered as an enclosing function parameter.
    if (isEnclosingFunctionParam(ArgExpr))
      return;

    ExplodedNode *N = C.addTransition(State);
    if (!N)
      return;
    initBugType();
    BugReport *Report = new BugReport(*BT,
        "Trying to free data which has not been allocated.", N);
    Report->addRange(ArgExpr->getSourceRange());
    if (AS)
      Report->markInteresting(AS->Region);
    C.emitReport(Report);
    return;
  }

  // Process functions which might deallocate.
  if (FunctionsToTrack[idx].Kind == PossibleAPI) {

    if (funName == "CFStringCreateWithBytesNoCopy") {
      const Expr *DeallocatorExpr = CE->getArg(5)->IgnoreParenCasts();
      // NULL ~ default deallocator, so warn.
      if (DeallocatorExpr->isNullPointerConstant(C.getASTContext(),
          Expr::NPC_ValueDependentIsNotNull)) {
        const AllocationPair AP = std::make_pair(ArgSM, AS);
        generateDeallocatorMismatchReport(AP, ArgExpr, C);
        return;
      }
      // One of the default allocators, so warn.
      if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(DeallocatorExpr)) {
        StringRef DeallocatorName = DE->getFoundDecl()->getName();
        if (DeallocatorName == "kCFAllocatorDefault" ||
            DeallocatorName == "kCFAllocatorSystemDefault" ||
            DeallocatorName == "kCFAllocatorMalloc") {
          const AllocationPair AP = std::make_pair(ArgSM, AS);
          generateDeallocatorMismatchReport(AP, ArgExpr, C);
          return;
        }
        // If kCFAllocatorNull, which does not deallocate, we still have to
        // find the deallocator.
        if (DE->getFoundDecl()->getName() == "kCFAllocatorNull")
          return;
      }
      // In all other cases, assume the user supplied a correct deallocator
      // that will free memory so stop tracking.
      State = State->remove<AllocatedData>(ArgSM);
      C.addTransition(State);
      return;
    }

    llvm_unreachable("We know of no other possible APIs.");
  }

  // The call is deallocating a value we previously allocated, so remove it
  // from the next state.
  State = State->remove<AllocatedData>(ArgSM);

  // Check if the proper deallocator is used.
  unsigned int PDeallocIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
  if (PDeallocIdx != idx || (FunctionsToTrack[idx].Kind == ErrorAPI)) {
    const AllocationPair AP = std::make_pair(ArgSM, AS);
    generateDeallocatorMismatchReport(AP, ArgExpr, C);
    return;
  }

  // If the buffer can be null and the return status can be an error,
  // report a bad call to free.
  if (State->assume(ArgSVal.castAs<DefinedSVal>(), false) &&
      !definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
    ExplodedNode *N = C.addTransition(State);
    if (!N)
      return;
    initBugType();
    BugReport *Report = new BugReport(*BT,
        "Only call free if a valid (non-NULL) buffer was returned.", N);
    Report->addVisitor(new SecKeychainBugVisitor(ArgSM));
    Report->addRange(ArgExpr->getSourceRange());
    Report->markInteresting(AS->Region);
    C.emitReport(Report);
    return;
  }

  C.addTransition(State);
}
Beispiel #22
0
void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
  if (!DS->isSingleDecl())
    return;
  
  const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
  if (!VD)
    return;

  ASTContext &Ctx = C.getASTContext();
  const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType());
  if (!VLA)
    return;

  // FIXME: Handle multi-dimensional VLAs.
  const Expr* SE = VLA->getSizeExpr();
  const GRState *state = C.getState();
  SVal sizeV = state->getSVal(SE);

  if (sizeV.isUndef()) {
    // Generate an error node.
    ExplodedNode *N = C.generateSink();
    if (!N)
      return;
    
    if (!BT_undef)
      BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a "
                                "garbage value as its size");

    EnhancedBugReport *report =
      new EnhancedBugReport(*BT_undef, BT_undef->getName(), N);
    report->addRange(SE->getSourceRange());
    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
    C.EmitReport(report);
    return;
  }

  // See if the size value is known. It can't be undefined because we would have
  // warned about that already.
  if (sizeV.isUnknown())
    return;
  
  // Check if the size is zero.
  DefinedSVal sizeD = cast<DefinedSVal>(sizeV);

  const GRState *stateNotZero, *stateZero;
  llvm::tie(stateNotZero, stateZero) = state->assume(sizeD);

  if (stateZero && !stateNotZero) {
    ExplodedNode* N = C.generateSink(stateZero);
    if (!BT_zero)
      BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero "
                               "size");

    EnhancedBugReport *report =
      new EnhancedBugReport(*BT_zero, BT_zero->getName(), N);
    report->addRange(SE->getSourceRange());
    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
    C.EmitReport(report);
    return;
  }
 
  // From this point on, assume that the size is not zero.
  state = stateNotZero;

  // VLASizeChecker is responsible for defining the extent of the array being
  // declared. We do this by multiplying the array length by the element size,
  // then matching that with the array region's extent symbol.

  // Convert the array length to size_t.
  SValBuilder &svalBuilder = C.getSValBuilder();
  QualType SizeTy = Ctx.getSizeType();
  NonLoc ArrayLength = cast<NonLoc>(svalBuilder.evalCast(sizeD, SizeTy, 
                                                         SE->getType()));

  // Get the element size.
  CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType());
  SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy);

  // Multiply the array length by the element size.
  SVal ArraySizeVal = svalBuilder.evalBinOpNN(state, BO_Mul, ArrayLength,
                                              cast<NonLoc>(EleSizeVal), SizeTy);

  // Finally, assume that the array's extent matches the given size.
  const LocationContext *LC = C.getPredecessor()->getLocationContext();
  DefinedOrUnknownSVal Extent =
    state->getRegion(VD, LC)->getExtent(svalBuilder);
  DefinedOrUnknownSVal ArraySize = cast<DefinedOrUnknownSVal>(ArraySizeVal);
  DefinedOrUnknownSVal sizeIsKnown =
    svalBuilder.evalEQ(state, Extent, ArraySize);
  state = state->assume(sizeIsKnown, true);

  // Assume should not fail at this point.
  assert(state);

  // Remember our assumptions!
  C.addTransition(state);
}
bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
                                      CheckerContext &C) const {
  ProgramStateRef state = C.getState();
  const FunctionDecl *FD = C.getCalleeDecl(CE);
  const LocationContext *LCtx = C.getLocationContext();
  if (!FD)
    return false;

  switch (FD->getBuiltinID()) {
  default:
    return false;

  case Builtin::BI__builtin_unpredictable:
  case Builtin::BI__builtin_expect:
  case Builtin::BI__builtin_assume_aligned:
  case Builtin::BI__builtin_addressof: {
    // For __builtin_unpredictable, __builtin_expect, and
    // __builtin_assume_aligned, just return the value of the subexpression.
    // __builtin_addressof is going from a reference to a pointer, but those
    // are represented the same way in the analyzer.
    assert (CE->arg_begin() != CE->arg_end());
    SVal X = state->getSVal(*(CE->arg_begin()), LCtx);
    C.addTransition(state->BindExpr(CE, LCtx, X));
    return true;
  }

  case Builtin::BI__builtin_alloca_with_align:
  case Builtin::BI__builtin_alloca: {
    // FIXME: Refactor into StoreManager itself?
    MemRegionManager& RM = C.getStoreManager().getRegionManager();
    const AllocaRegion* R =
      RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());

    // Set the extent of the region in bytes. This enables us to use the
    // SVal of the argument directly. If we save the extent in bits, we
    // cannot represent values like symbol*8.
    DefinedOrUnknownSVal Size =
        state->getSVal(*(CE->arg_begin()), LCtx).castAs<DefinedOrUnknownSVal>();

    SValBuilder& svalBuilder = C.getSValBuilder();
    DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
    DefinedOrUnknownSVal extentMatchesSizeArg =
      svalBuilder.evalEQ(state, Extent, Size);
    state = state->assume(extentMatchesSizeArg, true);
    assert(state && "The region should not have any previous constraints");

    C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
    return true;
  }

  case Builtin::BI__builtin_object_size: {
    // This must be resolvable at compile time, so we defer to the constant
    // evaluator for a value.
    SVal V = UnknownVal();
    llvm::APSInt Result;
    if (CE->EvaluateAsInt(Result, C.getASTContext(), Expr::SE_NoSideEffects)) {
      // Make sure the result has the correct type.
      SValBuilder &SVB = C.getSValBuilder();
      BasicValueFactory &BVF = SVB.getBasicValueFactory();
      BVF.getAPSIntType(CE->getType()).apply(Result);
      V = SVB.makeIntVal(Result);
    }

    C.addTransition(state->BindExpr(CE, LCtx, V));
    return true;
  }
  }
}
bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
                                               SVal V,
                                               SourceRange ArgRange,
                                               const Expr *ArgEx,
                                               bool IsFirstArgument,
                                               bool CheckUninitFields,
                                               const CallEvent &Call,
                                               std::unique_ptr<BugType> &BT,
                                               const ParmVarDecl *ParamDecl
                                               ) const {
  const char *BD = "Uninitialized argument value";

  if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD))
    return true;

  if (V.isUndef()) {
    if (ExplodedNode *N = C.generateSink()) {
      LazyInit_BT(BD, BT);

      // Generate a report for this bug.
      StringRef Desc =
          describeUninitializedArgumentInCall(Call, IsFirstArgument);
      auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
      R->addRange(ArgRange);
      if (ArgEx)
        bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
      C.emitReport(std::move(R));
    }
    return true;
  }

  if (!CheckUninitFields)
    return false;

  if (Optional<nonloc::LazyCompoundVal> LV =
          V.getAs<nonloc::LazyCompoundVal>()) {

    class FindUninitializedField {
    public:
      SmallVector<const FieldDecl *, 10> FieldChain;
    private:
      StoreManager &StoreMgr;
      MemRegionManager &MrMgr;
      Store store;
    public:
      FindUninitializedField(StoreManager &storeMgr,
                             MemRegionManager &mrMgr, Store s)
      : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}

      bool Find(const TypedValueRegion *R) {
        QualType T = R->getValueType();
        if (const RecordType *RT = T->getAsStructureType()) {
          const RecordDecl *RD = RT->getDecl()->getDefinition();
          assert(RD && "Referred record has no definition");
          for (const auto *I : RD->fields()) {
            const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
            FieldChain.push_back(I);
            T = I->getType();
            if (T->getAsStructureType()) {
              if (Find(FR))
                return true;
            }
            else {
              const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
              if (V.isUndef())
                return true;
            }
            FieldChain.pop_back();
          }
        }

        return false;
      }
    };

    const LazyCompoundValData *D = LV->getCVData();
    FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
                             C.getSValBuilder().getRegionManager(),
                             D->getStore());

    if (F.Find(D->getRegion())) {
      if (ExplodedNode *N = C.generateSink()) {
        LazyInit_BT(BD, BT);
        SmallString<512> Str;
        llvm::raw_svector_ostream os(Str);
        os << "Passed-by-value struct argument contains uninitialized data";

        if (F.FieldChain.size() == 1)
          os << " (e.g., field: '" << *F.FieldChain[0] << "')";
        else {
          os << " (e.g., via the field chain: '";
          bool first = true;
          for (SmallVectorImpl<const FieldDecl *>::iterator
               DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
            if (first)
              first = false;
            else
              os << '.';
            os << **DI;
          }
          os << "')";
        }

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

        // FIXME: enhance track back for uninitialized value for arbitrary
        // memregions
        C.emitReport(std::move(R));
      }
      return true;
    }
  }

  return false;
}
Beispiel #25
0
bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
                                               SVal V, SourceRange argRange,
                                               const Expr *argEx,
                                               const char *BT_desc,
                                               llvm::OwningPtr<BugType> &BT) {

  if (V.isUndef()) {
    if (ExplodedNode *N = C.generateSink()) {
      LazyInit_BT(BT_desc, BT);

      // Generate a report for this bug.
      BugReport *R = new BugReport(*BT, BT->getName(), N);
      R->addRange(argRange);
      if (argEx)
        R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx));
      C.EmitReport(R);
    }
    return true;
  }

  if (const nonloc::LazyCompoundVal *LV =
        dyn_cast<nonloc::LazyCompoundVal>(&V)) {

    class FindUninitializedField {
    public:
      SmallVector<const FieldDecl *, 10> FieldChain;
    private:
      ASTContext &C;
      StoreManager &StoreMgr;
      MemRegionManager &MrMgr;
      Store store;
    public:
      FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
                             MemRegionManager &mrMgr, Store s)
      : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}

      bool Find(const TypedValueRegion *R) {
        QualType T = R->getValueType();
        if (const RecordType *RT = T->getAsStructureType()) {
          const RecordDecl *RD = RT->getDecl()->getDefinition();
          assert(RD && "Referred record has no definition");
          for (RecordDecl::field_iterator I =
               RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
            const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
            FieldChain.push_back(*I);
            T = (*I)->getType();
            if (T->getAsStructureType()) {
              if (Find(FR))
                return true;
            }
            else {
              const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
              if (V.isUndef())
                return true;
            }
            FieldChain.pop_back();
          }
        }

        return false;
      }
    };

    const LazyCompoundValData *D = LV->getCVData();
    FindUninitializedField F(C.getASTContext(),
                             C.getState()->getStateManager().getStoreManager(),
                             C.getSValBuilder().getRegionManager(),
                             D->getStore());

    if (F.Find(D->getRegion())) {
      if (ExplodedNode *N = C.generateSink()) {
        LazyInit_BT(BT_desc, BT);
        llvm::SmallString<512> Str;
        llvm::raw_svector_ostream os(Str);
        os << "Passed-by-value struct argument contains uninitialized data";

        if (F.FieldChain.size() == 1)
          os << " (e.g., field: '" << *F.FieldChain[0] << "')";
        else {
          os << " (e.g., via the field chain: '";
          bool first = true;
          for (SmallVectorImpl<const FieldDecl *>::iterator
               DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
            if (first)
              first = false;
            else
              os << '.';
            os << **DI;
          }
          os << "')";
        }

        // Generate a report for this bug.
        BugReport *R = new BugReport(*BT, os.str(), N);
        R->addRange(argRange);

        // FIXME: enhance track back for uninitialized value for arbitrary
        // memregions
        C.EmitReport(R);
      }
      return true;
    }
  }

  return false;
}
Beispiel #26
0
void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
                                              const CallExpr* CE) {
  // If the CallExpr doesn't have exactly 1 argument just give up checking.
  if (CE->getNumArgs() != 1)
    return;

  // Get the function declaration of the callee.
  const GRState* state = C.getState();
  SVal X = state->getSVal(CE->getCallee());
  const FunctionDecl* FD = X.getAsFunctionDecl();

  if (!FD)
    return;
  
  if (!BT) {
    ASTContext &Ctx = C.getASTContext();
    Retain = &Ctx.Idents.get("CFRetain");
    Release = &Ctx.Idents.get("CFRelease");
    BT = new APIMisuse("null passed to CFRetain/CFRelease");
  }

  // Check if we called CFRetain/CFRelease.
  const IdentifierInfo *FuncII = FD->getIdentifier();
  if (!(FuncII == Retain || FuncII == Release))
    return;

  // FIXME: The rest of this just checks that the argument is non-null.
  // It should probably be refactored and combined with AttrNonNullChecker.

  // Get the argument's value.
  const Expr *Arg = CE->getArg(0);
  SVal ArgVal = state->getSVal(Arg);
  DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
  if (!DefArgVal)
    return;

  // Get a NULL value.
  SValBuilder &svalBuilder = C.getSValBuilder();
  DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));

  // Make an expression asserting that they're equal.
  DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);

  // Are they equal?
  const GRState *stateTrue, *stateFalse;
  llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);

  if (stateTrue && !stateFalse) {
    ExplodedNode *N = C.generateSink(stateTrue);
    if (!N)
      return;

    const char *description = (FuncII == Retain)
                            ? "Null pointer argument in call to CFRetain"
                            : "Null pointer argument in call to CFRelease";

    EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
    report->addRange(Arg->getSourceRange());
    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
    C.EmitReport(report);
    return;
  }

  // From here on, we know the argument is non-null.
  C.addTransition(stateFalse);
}
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
                                              const ProgramState *state,
                                              ObjCMessage msg) const {
  ASTContext &Ctx = C.getASTContext();

  // 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.getType(Ctx);

  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);

  if (CanRetTy->isStructureOrClassType()) {
    // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
    // have the "use of undefined value" be smarter about where the
    // undefined value came from.
    if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){
      if (ExplodedNode *N = C.generateSink(state))
        emitNilReceiverBug(C, msg, N);
      return;
    }

    // The result is not consumed by a surrounding expression.  Just propagate
    // the current state.
    C.addTransition(state);
    return;
  }

  // Other cases: check if the return type is smaller than void*.
  if (CanRetTy != Ctx.VoidTy &&
      C.getPredecessor()->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 (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))
        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(msg.getType(Ctx));
    C.generateNode(state->BindExpr(msg.getOriginExpr(), V));
    return;
  }

  C.addTransition(state);
}
Beispiel #28
0
void UnixAPIChecker::CheckOpenVariant(CheckerContext &C,
                                      const CallExpr *CE,
                                      OpenVariant Variant) const {
  // The index of the argument taking the flags open flags (O_RDONLY,
  // O_WRONLY, O_CREAT, etc.),
  unsigned int FlagsArgIndex;
  const char *VariantName;
  switch (Variant) {
  case OpenVariant::Open:
    FlagsArgIndex = 1;
    VariantName = "open";
    break;
  case OpenVariant::OpenAt:
    FlagsArgIndex = 2;
    VariantName = "openat";
    break;
  };

  // All calls should at least provide arguments up to the 'flags' parameter.
  unsigned int MinArgCount = FlagsArgIndex + 1;

  // If the flags has O_CREAT set then open/openat() require an additional
  // argument specifying the file mode (permission bits) for the created file.
  unsigned int CreateModeArgIndex = FlagsArgIndex + 1;

  // The create mode argument should be the last argument.
  unsigned int MaxArgCount = CreateModeArgIndex + 1;

  ProgramStateRef state = C.getState();

  if (CE->getNumArgs() < MinArgCount) {
    // The frontend should issue a warning for this case, so this is a sanity
    // check.
    return;
  } else if (CE->getNumArgs() == MaxArgCount) {
    const Expr *Arg = CE->getArg(CreateModeArgIndex);
    QualType QT = Arg->getType();
    if (!QT->isIntegerType()) {
      SmallString<256> SBuf;
      llvm::raw_svector_ostream OS(SBuf);
      OS << "The " << CreateModeArgIndex + 1
         << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
         << " argument to '" << VariantName << "' is not an integer";

      ReportOpenBug(C, state,
                    SBuf.c_str(),
                    Arg->getSourceRange());
      return;
    }
  } else if (CE->getNumArgs() > MaxArgCount) {
    SmallString<256> SBuf;
    llvm::raw_svector_ostream OS(SBuf);
    OS << "Call to '" << VariantName << "' with more than " << MaxArgCount
       << " arguments";

    ReportOpenBug(C, state,
                  SBuf.c_str(),
                  CE->getArg(MaxArgCount)->getSourceRange());
    return;
  }

  // The definition of O_CREAT is platform specific.  We need a better way
  // of querying this information from the checking environment.
  if (!Val_O_CREAT.hasValue()) {
    if (C.getASTContext().getTargetInfo().getTriple().getVendor()
                                                      == llvm::Triple::Apple)
      Val_O_CREAT = 0x0200;
    else {
      // FIXME: We need a more general way of getting the O_CREAT value.
      // We could possibly grovel through the preprocessor state, but
      // that would require passing the Preprocessor object to the ExprEngine.
      // See also: MallocChecker.cpp / M_ZERO.
      return;
    }
  }

  // Now check if oflags has O_CREAT set.
  const Expr *oflagsEx = CE->getArg(FlagsArgIndex);
  const SVal V = state->getSVal(oflagsEx, C.getLocationContext());
  if (!V.getAs<NonLoc>()) {
    // The case where 'V' can be a location can only be due to a bad header,
    // so in this case bail out.
    return;
  }
  NonLoc oflags = V.castAs<NonLoc>();
  NonLoc ocreateFlag = C.getSValBuilder()
      .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
  SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
                                                      oflags, ocreateFlag,
                                                      oflagsEx->getType());
  if (maskedFlagsUC.isUnknownOrUndef())
    return;
  DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();

  // Check if maskedFlags is non-zero.
  ProgramStateRef trueState, falseState;
  std::tie(trueState, falseState) = state->assume(maskedFlags);

  // Only emit an error if the value of 'maskedFlags' is properly
  // constrained;
  if (!(trueState && !falseState))
    return;

  if (CE->getNumArgs() < MaxArgCount) {
    SmallString<256> SBuf;
    llvm::raw_svector_ostream OS(SBuf);
    OS << "Call to '" << VariantName << "' requires a "
       << CreateModeArgIndex + 1
       << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
       << " argument when the 'O_CREAT' flag is set";
    ReportOpenBug(C, trueState,
                  SBuf.c_str(),
                  oflagsEx->getSourceRange());
  }
}
void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
                                          CheckerContext &C) const {
  // If the CallExpr doesn't have exactly 1 argument just give up checking.
  if (CE->getNumArgs() != 1)
    return;

  ProgramStateRef state = C.getState();
  const FunctionDecl *FD = C.getCalleeDecl(CE);
  if (!FD)
    return;

  if (!BT) {
    ASTContext &Ctx = C.getASTContext();
    Retain = &Ctx.Idents.get("CFRetain");
    Release = &Ctx.Idents.get("CFRelease");
    MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
    Autorelease = &Ctx.Idents.get("CFAutorelease");
    BT.reset(new APIMisuse(
        this, "null passed to CF memory management function"));
  }

  // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
  const IdentifierInfo *FuncII = FD->getIdentifier();
  if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable ||
        FuncII == Autorelease))
    return;

  // FIXME: The rest of this just checks that the argument is non-null.
  // It should probably be refactored and combined with NonNullParamChecker.

  // Get the argument's value.
  const Expr *Arg = CE->getArg(0);
  SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
  Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
  if (!DefArgVal)
    return;

  // Get a NULL value.
  SValBuilder &svalBuilder = C.getSValBuilder();
  DefinedSVal zero =
      svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();

  // Make an expression asserting that they're equal.
  DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);

  // Are they equal?
  ProgramStateRef stateTrue, stateFalse;
  std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);

  if (stateTrue && !stateFalse) {
    ExplodedNode *N = C.generateErrorNode(stateTrue);
    if (!N)
      return;

    const char *description;
    if (FuncII == Retain)
      description = "Null pointer argument in call to CFRetain";
    else if (FuncII == Release)
      description = "Null pointer argument in call to CFRelease";
    else if (FuncII == MakeCollectable)
      description = "Null pointer argument in call to CFMakeCollectable";
    else if (FuncII == Autorelease)
      description = "Null pointer argument in call to CFAutorelease";
    else
      llvm_unreachable("impossible case");

    auto report = llvm::make_unique<BugReport>(*BT, description, N);
    report->addRange(Arg->getSourceRange());
    bugreporter::trackNullOrUndefValue(N, Arg, *report);
    C.emitReport(std::move(report));
    return;
  }

  // From here on, we know the argument is non-null.
  C.addTransition(stateFalse);
}
void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
                                        const Stmt* LoadS,
                                        CheckerContext &checkerContext) const {

  // NOTE: Instead of using ProgramState::assumeInBound(), we are prototyping
  // some new logic here that reasons directly about memory region extents.
  // Once that logic is more mature, we can bring it back to assumeInBound()
  // for all clients to use.
  //
  // The algorithm we are using here for bounds checking is to see if the
  // memory access is within the extent of the base region.  Since we
  // have some flexibility in defining the base region, we can achieve
  // various levels of conservatism in our buffer overflow checking.
  ProgramStateRef state = checkerContext.getState();  
  ProgramStateRef originalState = state;

  SValBuilder &svalBuilder = checkerContext.getSValBuilder();
  const RegionRawOffsetV2 &rawOffset = 
    RegionRawOffsetV2::computeOffset(state, svalBuilder, location);

  if (!rawOffset.getRegion())
    return;

  // CHECK LOWER BOUND: Is byteOffset < extent begin?  
  //  If so, we are doing a load/store
  //  before the first valid offset in the memory region.

  SVal extentBegin = computeExtentBegin(svalBuilder, rawOffset.getRegion());
  
  if (isa<NonLoc>(extentBegin)) {
    SVal lowerBound
      = svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(),
                                cast<NonLoc>(extentBegin),
                                svalBuilder.getConditionType());

    NonLoc *lowerBoundToCheck = dyn_cast<NonLoc>(&lowerBound);
    if (!lowerBoundToCheck)
      return;
    
    ProgramStateRef state_precedesLowerBound, state_withinLowerBound;
    llvm::tie(state_precedesLowerBound, state_withinLowerBound) =
      state->assume(*lowerBoundToCheck);

    // Are we constrained enough to definitely precede the lower bound?
    if (state_precedesLowerBound && !state_withinLowerBound) {
      reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes);
      return;
    }
  
    // Otherwise, assume the constraint of the lower bound.
    assert(state_withinLowerBound);
    state = state_withinLowerBound;
  }
  
  do {
    // CHECK UPPER BOUND: Is byteOffset >= extent(baseRegion)?  If so,
    // we are doing a load/store after the last valid offset.
    DefinedOrUnknownSVal extentVal =
      rawOffset.getRegion()->getExtent(svalBuilder);
    if (!isa<NonLoc>(extentVal))
      break;

    SVal upperbound
      = svalBuilder.evalBinOpNN(state, BO_GE, rawOffset.getByteOffset(),
                                cast<NonLoc>(extentVal),
                                svalBuilder.getConditionType());
  
    NonLoc *upperboundToCheck = dyn_cast<NonLoc>(&upperbound);
    if (!upperboundToCheck)
      break;
  
    ProgramStateRef state_exceedsUpperBound, state_withinUpperBound;
    llvm::tie(state_exceedsUpperBound, state_withinUpperBound) =
      state->assume(*upperboundToCheck);

    // If we are under constrained and the index variables are tainted, report.
    if (state_exceedsUpperBound && state_withinUpperBound) {
      if (state->isTainted(rawOffset.getByteOffset()))
        reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted);
        return;
    }
  
    // If we are constrained enough to definitely exceed the upper bound, report.
    if (state_exceedsUpperBound) {
      assert(!state_withinUpperBound);
      reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
      return;
    }
  
    assert(state_withinUpperBound);
    state = state_withinUpperBound;
  }
  while (false);
  
  if (state != originalState)
    checkerContext.addTransition(state);
}