Ejemplo n.º 1
0
CallEventRef<>
CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
                            ProgramStateRef State) {
  const LocationContext *ParentCtx = CalleeCtx->getParent();
  const LocationContext *CallerCtx = ParentCtx->getCurrentStackFrame();
  assert(CallerCtx && "This should not be used for top-level stack frames");

  const Stmt *CallSite = CalleeCtx->getCallSite();

  if (CallSite) {
    if (const CallExpr *CE = dyn_cast<CallExpr>(CallSite))
      return getSimpleCall(CE, State, CallerCtx);

    switch (CallSite->getStmtClass()) {
    case Stmt::CXXConstructExprClass:
    case Stmt::CXXTemporaryObjectExprClass: {
      SValBuilder &SVB = State->getStateManager().getSValBuilder();
      const CXXMethodDecl *Ctor = cast<CXXMethodDecl>(CalleeCtx->getDecl());
      Loc ThisPtr = SVB.getCXXThis(Ctor, CalleeCtx);
      SVal ThisVal = State->getSVal(ThisPtr);

      return getCXXConstructorCall(cast<CXXConstructExpr>(CallSite),
                                   ThisVal.getAsRegion(), State, CallerCtx);
    }
    case Stmt::CXXNewExprClass:
      return getCXXAllocatorCall(cast<CXXNewExpr>(CallSite), State, CallerCtx);
    case Stmt::ObjCMessageExprClass:
      return getObjCMethodCall(cast<ObjCMessageExpr>(CallSite),
                               State, CallerCtx);
    default:
      llvm_unreachable("This is not an inlineable statement.");
    }
  }

  // Fall back to the CFG. The only thing we haven't handled yet is
  // destructors, though this could change in the future.
  const CFGBlock *B = CalleeCtx->getCallSiteBlock();
  CFGElement E = (*B)[CalleeCtx->getIndex()];
  assert(E.getAs<CFGImplicitDtor>() &&
         "All other CFG elements should have exprs");
  assert(!E.getAs<CFGTemporaryDtor>() && "We don't handle temporaries yet");

  SValBuilder &SVB = State->getStateManager().getSValBuilder();
  const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CalleeCtx->getDecl());
  Loc ThisPtr = SVB.getCXXThis(Dtor, CalleeCtx);
  SVal ThisVal = State->getSVal(ThisPtr);

  const Stmt *Trigger;
  if (Optional<CFGAutomaticObjDtor> AutoDtor = E.getAs<CFGAutomaticObjDtor>())
    Trigger = AutoDtor->getTriggerStmt();
  else if (Optional<CFGDeleteDtor> DeleteDtor = E.getAs<CFGDeleteDtor>())
    Trigger = cast<Stmt>(DeleteDtor->getDeleteExpr());
  else
    Trigger = Dtor->getBody();

  return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(),
                              E.getAs<CFGBaseDtor>().hasValue(), State,
                              CallerCtx);
}
Ejemplo n.º 2
0
// Registers every VarDecl inside a Stmt with a last store visitor.
void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
                                                       const Stmt *S) {
  const ExplodedNode *N = BR.getErrorNode();
  std::deque<const Stmt *> WorkList;
  WorkList.push_back(S);

  while (!WorkList.empty()) {
    const Stmt *Head = WorkList.front();
    WorkList.pop_front();

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

    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) {
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        const VarRegion *R =
        StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());

        // What did we load?
        SVal V = state->getSVal(S, N->getLocationContext());

        if (V.getAs<loc::ConcreteInt>() || V.getAs<nonloc::ConcreteInt>()) {
          // Register a new visitor with the BugReport.
          BR.addVisitor(new FindLastStoreBRVisitor(V.castAs<KnownSVal>(), R));
        }
      }
    }

    for (Stmt::const_child_iterator I = Head->child_begin();
        I != Head->child_end(); ++I)
      WorkList.push_back(*I);
  }
}
Ejemplo n.º 3
0
/// Remove the Value requiring a release from the tracked set for
/// Instance and return the resultant state.
ProgramStateRef ObjCDeallocChecker::removeValueRequiringRelease(
    ProgramStateRef State, SymbolRef Instance, SymbolRef Value) const {
  assert(Instance);
  assert(Value);
  const ObjCIvarRegion *RemovedRegion = getIvarRegionForIvarSymbol(Value);
  if (!RemovedRegion)
    return State;

  const SymbolSet *Unreleased = State->get<UnreleasedIvarMap>(Instance);
  if (!Unreleased)
    return State;

  // Mark the value as no longer requiring a release.
  SymbolSet::Factory &F = State->getStateManager().get_context<SymbolSet>();
  SymbolSet NewUnreleased = *Unreleased;
  for (auto &Sym : *Unreleased) {
    const ObjCIvarRegion *UnreleasedRegion = getIvarRegionForIvarSymbol(Sym);
    assert(UnreleasedRegion);
    if (RemovedRegion->getDecl() == UnreleasedRegion->getDecl()) {
      NewUnreleased = F.remove(NewUnreleased, Sym);
    }
  }

  if (NewUnreleased.isEmpty()) {
    return State->remove<UnreleasedIvarMap>(Instance);
  }

  return State->set<UnreleasedIvarMap>(Instance, NewUnreleased);
}
Ejemplo n.º 4
0
ProgramStateRef taint::addTaint(ProgramStateRef State, SVal V,
                                TaintTagType Kind) {
  SymbolRef Sym = V.getAsSymbol();
  if (Sym)
    return addTaint(State, Sym, Kind);

  // If the SVal represents a structure, try to mass-taint all values within the
  // structure. For now it only works efficiently on lazy compound values that
  // were conjured during a conservative evaluation of a function - either as
  // return values of functions that return structures or arrays by value, or as
  // values of structures or arrays passed into the function by reference,
  // directly or through pointer aliasing. Such lazy compound values are
  // characterized by having exactly one binding in their captured store within
  // their parent region, which is a conjured symbol default-bound to the base
  // region of the parent region.
  if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
    if (Optional<SVal> binding =
            State->getStateManager().getStoreManager()
                                    .getDefaultBinding(*LCV)) {
      if (SymbolRef Sym = binding->getAsSymbol())
        return addPartialTaint(State, Sym, LCV->getRegion(), Kind);
    }
  }

  const MemRegion *R = V.getAsRegion();
  return addTaint(State, R, Kind);
}
Ejemplo n.º 5
0
void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
  ProgramStateRef state = C.getState();
  ProgramStateManager &Mgr = state->getStateManager();

  // If there are no jail state in the GDM, just return.
  const void *k = state->FindGDM(ChrootChecker::getTag());
  if (!k)
    return;

  // After chdir("/"), enter the jail, set the enum value JAIL_ENTERED.
  const Expr *ArgExpr = CE->getArg(0);
  SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext());
  
  if (const MemRegion *R = ArgVal.getAsRegion()) {
    R = R->StripCasts();
    if (const StringRegion* StrRegion= dyn_cast<StringRegion>(R)) {
      const StringLiteral* Str = StrRegion->getStringLiteral();
      if (Str->getString() == "/")
        state = Mgr.addGDM(state, ChrootChecker::getTag(),
                           (void*) JAIL_ENTERED);
    }
  }

  C.addTransition(state);
}
Ejemplo n.º 6
0
void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
  ProgramStateRef state = C.getState();
  ProgramStateManager &Mgr = state->getStateManager();
  
  // Once encouter a chroot(), set the enum value ROOT_CHANGED directly in 
  // the GDM.
  state = Mgr.addGDM(state, ChrootChecker::getTag(), (void*) ROOT_CHANGED);
  C.addTransition(state);
}
Ejemplo n.º 7
0
/// If this is the beginning of -dealloc, mark the values initially stored in
/// instance variables that must be released by the end of -dealloc
/// as unreleased in the state.
void ObjCDeallocChecker::checkBeginFunction(
    CheckerContext &C) const {
  initIdentifierInfoAndSelectors(C.getASTContext());

  // Only do this if the current method is -dealloc.
  SVal SelfVal;
  if (!isInInstanceDealloc(C, SelfVal))
    return;

  SymbolRef SelfSymbol = SelfVal.getAsSymbol();

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

  ProgramStateRef State = InitialState;

  SymbolSet::Factory &F = State->getStateManager().get_context<SymbolSet>();

  // Symbols that must be released by the end of the -dealloc;
  SymbolSet RequiredReleases = F.getEmptySet();

  // If we're an inlined -dealloc, we should add our symbols to the existing
  // set from our subclass.
  if (const SymbolSet *CurrSet = State->get<UnreleasedIvarMap>(SelfSymbol))
    RequiredReleases = *CurrSet;

  for (auto *PropImpl : getContainingObjCImpl(LCtx)->property_impls()) {
    ReleaseRequirement Requirement = getDeallocReleaseRequirement(PropImpl);
    if (Requirement != ReleaseRequirement::MustRelease)
      continue;

    SVal LVal = State->getLValue(PropImpl->getPropertyIvarDecl(), SelfVal);
    Optional<Loc> LValLoc = LVal.getAs<Loc>();
    if (!LValLoc)
      continue;

    SVal InitialVal = State->getSVal(LValLoc.getValue());
    SymbolRef Symbol = InitialVal.getAsSymbol();
    if (!Symbol || !isa<SymbolRegionValue>(Symbol))
      continue;

    // Mark the value as requiring a release.
    RequiredReleases = F.add(RequiredReleases, Symbol);
  }

  if (!RequiredReleases.isEmpty()) {
    State = State->set<UnreleasedIvarMap>(SelfSymbol, RequiredReleases);
  }

  if (State != InitialState) {
    C.addTransition(State);
  }
}
Ejemplo n.º 8
0
/// Returns a region representing the first element of a (possibly
/// multi-dimensional) array.
///
/// On return, \p Ty will be set to the base type of the array.
///
/// If the type is not an array type at all, the original value is returned.
static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue,
                                  QualType &Ty) {
  SValBuilder &SVB = State->getStateManager().getSValBuilder();
  ASTContext &Ctx = SVB.getContext();

  while (const ArrayType *AT = Ctx.getAsArrayType(Ty)) {
    Ty = AT->getElementType();
    LValue = State->getLValue(Ty, SVB.makeZeroArrayIndex(), LValue);
  }

  return LValue;
}
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State,
                                                DefinedSVal Cond,
                                                bool Assumption) {
  // If we have a Loc value, cast it to a bool NonLoc first.
  if (Optional<Loc> LV = Cond.getAs<Loc>()) {
    SValBuilder &SVB = State->getStateManager().getSValBuilder();
    QualType T;
    const MemRegion *MR = LV->getAsRegion();
    if (const TypedRegion *TR = dyn_cast_or_null<TypedRegion>(MR))
      T = TR->getLocationType();
    else
      T = SVB.getContext().VoidPtrTy;

    Cond = SVB.evalCast(*LV, SVB.getContext().BoolTy, T).castAs<DefinedSVal>();
  }

  return assume(State, Cond.castAs<NonLoc>(), Assumption);
}
void InnerPointerChecker::checkPostCall(const CallEvent &Call,
                                        CheckerContext &C) const {
  ProgramStateRef State = C.getState();

  if (const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) {
    // TODO: Do we need these to be typed?
    const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
        ICall->getCXXThisVal().getAsRegion());
    if (!ObjRegion)
      return;

    if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
      SVal RawPtr = Call.getReturnValue();
      if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
        // Start tracking this raw pointer by adding it to the set of symbols
        // associated with this container object in the program state map.

        PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
        const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
        PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
        assert(C.wasInlined || !Set.contains(Sym));
        Set = F.add(Set, Sym);

        State = State->set<RawPtrMap>(ObjRegion, Set);
        C.addTransition(State);
      }
      return;
    }

    // Check [string.require] / second point.
    if (isInvalidatingMemberFunction(Call)) {
      markPtrSymbolsReleased(Call, State, ObjRegion, C);
      return;
    }
  }

  // Check [string.require] / first point.
  checkFunctionArguments(Call, State, C);
}
void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper,
                                           CheckerContext &C) const {
  ProgramStateRef State = C.getState();
  PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
  RawPtrMapTy RPM = State->get<RawPtrMap>();
  for (const auto Entry : RPM) {
    if (!SymReaper.isLiveRegion(Entry.first)) {
      // Due to incomplete destructor support, some dead regions might
      // remain in the program state map. Clean them up.
      State = State->remove<RawPtrMap>(Entry.first);
    }
    if (const PtrSet *OldSet = State->get<RawPtrMap>(Entry.first)) {
      PtrSet CleanedUpSet = *OldSet;
      for (const auto Symbol : Entry.second) {
        if (!SymReaper.isLive(Symbol))
          CleanedUpSet = F.remove(CleanedUpSet, Symbol);
      }
      State = CleanedUpSet.isEmpty()
                  ? State->remove<RawPtrMap>(Entry.first)
                  : State->set<RawPtrMap>(Entry.first, CleanedUpSet);
    }
  }
  C.addTransition(State);
}
static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
                                           const LocationContext *LCtx,
                                           const RefVal &CurrV, SymbolRef &Sym,
                                           const Stmt *S,
                                           llvm::raw_string_ostream &os) {
  CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager();
  if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
    // Get the name of the callee (if it is available)
    // from the tracked SVal.
    SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
    const FunctionDecl *FD = X.getAsFunctionDecl();

    // If failed, try to get it from AST.
    if (!FD)
      FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());

    if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) {
      os << "Call to method '" << MD->getQualifiedNameAsString() << '\'';
    } else if (FD) {
      os << "Call to function '" << FD->getQualifiedNameAsString() << '\'';
    } else {
      os << "function call";
    }
  } else if (isa<CXXNewExpr>(S)) {
    os << "Operator 'new'";
  } else {
    assert(isa<ObjCMessageExpr>(S));
    CallEventRef<ObjCMethodCall> Call =
        Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx);

    switch (Call->getMessageKind()) {
    case OCM_Message:
      os << "Method";
      break;
    case OCM_PropertyAccess:
      os << "Property";
      break;
    case OCM_Subscript:
      os << "Subscript";
      break;
    }
  }

  Optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx);
  auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE);

  // If index is not found, we assume that the symbol was returned.
  if (!Idx) {
    os << " returns ";
  } else {
    os << " writes ";
  }

  if (CurrV.getObjKind() == ObjKind::CF) {
    os << "a Core Foundation object of type '"
       << Sym->getType().getAsString() << "' with a ";
  } else if (CurrV.getObjKind() == ObjKind::OS) {
    os << "an OSObject of type '" << getPrettyTypeName(Sym->getType())
       << "' with a ";
  } else if (CurrV.getObjKind() == ObjKind::Generalized) {
    os << "an object of type '" << Sym->getType().getAsString()
       << "' with a ";
  } else {
    assert(CurrV.getObjKind() == ObjKind::ObjC);
    QualType T = Sym->getType();
    if (!isa<ObjCObjectPointerType>(T)) {
      os << "an Objective-C object with a ";
    } else {
      const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T);
      os << "an instance of " << PT->getPointeeType().getAsString()
         << " with a ";
    }
  }

  if (CurrV.isOwned()) {
    os << "+1 retain count";
  } else {
    assert(CurrV.isNotOwned());
    os << "+0 retain count";
  }

  if (Idx) {
    os << " into an out parameter '";
    const ParmVarDecl *PVD = (*CE)->parameters()[*Idx];
    PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(),
                              /*Qualified=*/false);
    os << "'";

    QualType RT = (*CE)->getResultType();
    if (!RT.isNull() && !RT->isVoidType()) {
      SVal RV = (*CE)->getReturnValue();
      if (CurrSt->isNull(RV).isConstrainedTrue()) {
        os << " (assuming the call returns zero)";
      } else if (CurrSt->isNonNull(RV).isConstrainedTrue()) {
        os << " (assuming the call returns non-zero)";
      }

    }
  }
}
void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const {
  ProgramStateRef state = Ctx.getState();

  // Iterate over all bindings to global variables and see if it contains
  // a memory region in the stack space.
  class CallBack : public StoreManager::BindingsHandler {
  private:
    CheckerContext &Ctx;
    const StackFrameContext *CurSFC;
  public:
    SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;

    CallBack(CheckerContext &CC) :
      Ctx(CC),
      CurSFC(CC.getLocationContext()->getCurrentStackFrame())
    {}
    
    bool HandleBinding(StoreManager &SMgr, Store store,
                       const MemRegion *region, SVal val) {
      
      if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
        return true;
      
      const MemRegion *vR = val.getAsRegion();
      if (!vR)
        return true;
        
      // Under automated retain release, it is okay to assign a block
      // directly to a global variable.
      if (Ctx.getASTContext().getLangOpts().ObjCAutoRefCount &&
          isa<BlockDataRegion>(vR))
        return true;

      if (const StackSpaceRegion *SSR = 
          dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
        // If the global variable holds a location in the current stack frame,
        // record the binding to emit a warning.
        if (SSR->getStackFrame() == CurSFC)
          V.push_back(std::make_pair(region, vR));
      }
      
      return true;
    }
  };
    
  CallBack cb(Ctx);
  state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);

  if (cb.V.empty())
    return;

  // Generate an error node.
  ExplodedNode *N = Ctx.addTransition(state);
  if (!N)
    return;

  if (!BT_stackleak)
    BT_stackleak.reset(
      new BuiltinBug("Stack address stored into global variable",
                     "Stack address was saved into a global variable. "
                     "This is dangerous because the address will become "
                     "invalid after returning from the function"));
  
  for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
    // Generate a report for this bug.
    SmallString<512> buf;
    llvm::raw_svector_ostream os(buf);
    SourceRange range = GenName(os, cb.V[i].second,
                                Ctx.getSourceManager());
    os << " is still referred to by the global variable '";
    const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
    os << *VR->getDecl()
       << "' upon returning to the caller.  This will be a dangling reference";
    BugReport *report = new BugReport(*BT_stackleak, os.str(), N);
    if (range.isValid())
      report->addRange(range);

    Ctx.EmitReport(report);
  }
}
Ejemplo n.º 14
0
 Simplifier(ProgramStateRef State)
     : State(State), SVB(State->getStateManager().getSValBuilder()) {}
Ejemplo n.º 15
0
/// Report any unreleased instance variables for the current instance being
/// dealloced.
void ObjCDeallocChecker::diagnoseMissingReleases(CheckerContext &C) const {
  ProgramStateRef State = C.getState();

  SVal SelfVal;
  if (!isInInstanceDealloc(C, SelfVal))
    return;

  const MemRegion *SelfRegion = SelfVal.castAs<loc::MemRegionVal>().getRegion();
  const LocationContext *LCtx = C.getLocationContext();

  ExplodedNode *ErrNode = nullptr;

  SymbolRef SelfSym = SelfVal.getAsSymbol();
  if (!SelfSym)
    return;

  const SymbolSet *OldUnreleased = State->get<UnreleasedIvarMap>(SelfSym);
  if (!OldUnreleased)
    return;

  SymbolSet NewUnreleased = *OldUnreleased;
  SymbolSet::Factory &F = State->getStateManager().get_context<SymbolSet>();

  ProgramStateRef InitialState = State;

  for (auto *IvarSymbol : *OldUnreleased) {
    const TypedValueRegion *TVR =
        cast<SymbolRegionValue>(IvarSymbol)->getRegion();
    const ObjCIvarRegion *IvarRegion = cast<ObjCIvarRegion>(TVR);

    // Don't warn if the ivar is not for this instance.
    if (SelfRegion != IvarRegion->getSuperRegion())
      continue;

    const ObjCIvarDecl *IvarDecl = IvarRegion->getDecl();
    // Prevent an inlined call to -dealloc in a super class from warning
    // about the values the subclass's -dealloc should release.
    if (IvarDecl->getContainingInterface() !=
        cast<ObjCMethodDecl>(LCtx->getDecl())->getClassInterface())
      continue;

    // Prevents diagnosing multiple times for the same instance variable
    // at, for example, both a return and at the end of the function.
    NewUnreleased = F.remove(NewUnreleased, IvarSymbol);

    if (State->getStateManager()
            .getConstraintManager()
            .isNull(State, IvarSymbol)
            .isConstrainedTrue()) {
      continue;
    }

    // A missing release manifests as a leak, so treat as a non-fatal error.
    if (!ErrNode)
      ErrNode = C.generateNonFatalErrorNode();
    // If we've already reached this node on another path, return without
    // diagnosing.
    if (!ErrNode)
      return;

    std::string Buf;
    llvm::raw_string_ostream OS(Buf);

    const ObjCInterfaceDecl *Interface = IvarDecl->getContainingInterface();
    // If the class is known to have a lifecycle with teardown that is
    // separate from -dealloc, do not warn about missing releases. We
    // suppress here (rather than not tracking for instance variables in
    // such classes) because these classes are rare.
    if (classHasSeparateTeardown(Interface))
      return;

    ObjCImplDecl *ImplDecl = Interface->getImplementation();

    const ObjCPropertyImplDecl *PropImpl =
        ImplDecl->FindPropertyImplIvarDecl(IvarDecl->getIdentifier());

    const ObjCPropertyDecl *PropDecl = PropImpl->getPropertyDecl();

    assert(PropDecl->getSetterKind() == ObjCPropertyDecl::Copy ||
           PropDecl->getSetterKind() == ObjCPropertyDecl::Retain);

    OS << "The '" << *IvarDecl << "' ivar in '" << *ImplDecl
       << "' was ";

    if (PropDecl->getSetterKind() == ObjCPropertyDecl::Retain)
      OS << "retained";
    else
      OS << "copied";

    OS << " by a synthesized property but not released"
          " before '[super dealloc]'";

    std::unique_ptr<BugReport> BR(
        new BugReport(*MissingReleaseBugType, OS.str(), ErrNode));

    C.emitReport(std::move(BR));
  }

  if (NewUnreleased.isEmpty()) {
    State = State->remove<UnreleasedIvarMap>(SelfSym);
  } else {
    State = State->set<UnreleasedIvarMap>(SelfSym, NewUnreleased);
  }

  if (ErrNode) {
    C.addTransition(State, ErrNode);
  } else if (State != InitialState) {
    C.addTransition(State);
  }

  // Make sure that after checking in the top-most frame the list of
  // tracked ivars is empty. This is intended to detect accidental leaks in
  // the UnreleasedIvarMap program state.
  assert(!LCtx->inTopFrame() || State->get<UnreleasedIvarMap>().isEmpty());
}
Ejemplo n.º 16
0
void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const {
  if (!ChecksEnabled[CK_StackAddrEscapeChecker])
    return;

  ProgramStateRef State = Ctx.getState();

  // Iterate over all bindings to global variables and see if it contains
  // a memory region in the stack space.
  class CallBack : public StoreManager::BindingsHandler {
  private:
    CheckerContext &Ctx;
    const StackFrameContext *CurSFC;

  public:
    SmallVector<std::pair<const MemRegion *, const MemRegion *>, 10> V;

    CallBack(CheckerContext &CC)
        : Ctx(CC), CurSFC(CC.getLocationContext()->getCurrentStackFrame()) {}

    bool HandleBinding(StoreManager &SMgr, Store S, const MemRegion *Region,
                       SVal Val) override {

      if (!isa<GlobalsSpaceRegion>(Region->getMemorySpace()))
        return true;
      const MemRegion *VR = Val.getAsRegion();
      if (VR && isa<StackSpaceRegion>(VR->getMemorySpace()) &&
          !isArcManagedBlock(VR, Ctx) && !isNotInCurrentFrame(VR, Ctx))
        V.emplace_back(Region, VR);
      return true;
    }
  };

  CallBack Cb(Ctx);
  State->getStateManager().getStoreManager().iterBindings(State->getStore(),
                                                          Cb);

  if (Cb.V.empty())
    return;

  // Generate an error node.
  ExplodedNode *N = Ctx.generateNonFatalErrorNode(State);
  if (!N)
    return;

  if (!BT_stackleak)
    BT_stackleak = llvm::make_unique<BuiltinBug>(
        this, "Stack address stored into global variable",
        "Stack address was saved into a global variable. "
        "This is dangerous because the address will become "
        "invalid after returning from the function");

  for (const auto &P : Cb.V) {
    // Generate a report for this bug.
    SmallString<128> Buf;
    llvm::raw_svector_ostream Out(Buf);
    SourceRange Range = genName(Out, P.second, Ctx.getASTContext());
    Out << " is still referred to by the ";
    if (isa<StaticGlobalSpaceRegion>(P.first->getMemorySpace()))
      Out << "static";
    else
      Out << "global";
    Out << " variable '";
    const VarRegion *VR = cast<VarRegion>(P.first->getBaseRegion());
    Out << *VR->getDecl()
        << "' upon returning to the caller.  This will be a dangling reference";
    auto Report = llvm::make_unique<BugReport>(*BT_stackleak, Out.str(), N);
    if (Range.isValid())
      Report->addRange(Range);

    Ctx.emitReport(std::move(Report));
  }
}
Ejemplo n.º 17
0
bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode,
                                        const Stmt *S,
                                        BugReport &report, bool IsArg) {
  if (!S || !ErrorNode)
    return false;

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

  const ExplodedNode *N = ErrorNode;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

  return true;
}
Ejemplo n.º 19
0
static DefinedSVal getLocFromSymbol(const ProgramStateRef &State,
                                    SymbolRef Sym) {
  const MemRegion *R =
      State->getStateManager().getRegionManager().getSymbolicRegion(Sym);
  return loc::MemRegionVal(R);
}