static bool
checkSelfIvarsForInvariantViolation(ProgramStateRef State,
                                    const LocationContext *LocCtxt) {
  auto *MD = dyn_cast<ObjCMethodDecl>(LocCtxt->getDecl());
  if (!MD || !MD->isInstanceMethod())
    return false;

  const ImplicitParamDecl *SelfDecl = LocCtxt->getSelfDecl();
  if (!SelfDecl)
    return false;

  SVal SelfVal = State->getSVal(State->getRegion(SelfDecl, LocCtxt));

  const ObjCObjectPointerType *SelfType =
      dyn_cast<ObjCObjectPointerType>(SelfDecl->getType());
  if (!SelfType)
    return false;

  const ObjCInterfaceDecl *ID = SelfType->getInterfaceDecl();
  if (!ID)
    return false;

  for (const auto *IvarDecl : ID->ivars()) {
    SVal LV = State->getLValue(IvarDecl, SelfVal);
    if (checkValueAtLValForInvariantViolation(State, LV, IvarDecl->getType())) {
      return true;
    }
  }
  return false;
}
Example #2
0
/// Returns true if LCtx is a call to -dealloc and false
/// otherwise. If true, it also sets SelfValOut to the value of
/// 'self'.
bool ObjCDeallocChecker::isInInstanceDealloc(const CheckerContext &C,
                                             const LocationContext *LCtx,
                                             SVal &SelfValOut) const {
  auto *MD = dyn_cast<ObjCMethodDecl>(LCtx->getDecl());
  if (!MD || !MD->isInstanceMethod() || MD->getSelector() != DeallocSel)
    return false;

  const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
  assert(SelfDecl && "No self in -dealloc?");

  ProgramStateRef State = C.getState();
  SelfValOut = State->getSVal(State->getRegion(SelfDecl, LCtx));
  return true;
}
Example #3
0
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
                               ExplodedNodeSet &Dst) {
  
  // FIXME: static variables may have an initializer, but the second
  //  time a function is called those values may not be current.
  //  This may need to be reflected in the CFG.
  
  // Assumption: The CFG has one DeclStmt per Decl.
  const Decl *D = *DS->decl_begin();
  
  if (!D || !isa<VarDecl>(D)) {
    //TODO:AZ: remove explicit insertion after refactoring is done.
    Dst.insert(Pred);
    return;
  }
  
  // FIXME: all pre/post visits should eventually be handled by ::Visit().
  ExplodedNodeSet dstPreVisit;
  getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
  
  StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext);
  const VarDecl *VD = dyn_cast<VarDecl>(D);
  for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
       I!=E; ++I) {
    ExplodedNode *N = *I;
    ProgramStateRef state = N->getState();
    
    // Decls without InitExpr are not initialized explicitly.
    const LocationContext *LC = N->getLocationContext();
    
    if (const Expr *InitEx = VD->getInit()) {
      SVal InitVal = state->getSVal(InitEx, LC);

      if (InitVal == state->getLValue(VD, LC) ||
          (VD->getType()->isArrayType() &&
           isa<CXXConstructExpr>(InitEx->IgnoreImplicit()))) {
        // We constructed the object directly in the variable.
        // No need to bind anything.
        B.generateNode(DS, N, state);
      } else {
        // We bound the temp obj region to the CXXConstructExpr. Now recover
        // the lazy compound value when the variable is not a reference.
        if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() && 
            !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
          InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
          assert(isa<nonloc::LazyCompoundVal>(InitVal));
        }
        
        // Recover some path-sensitivity if a scalar value evaluated to
        // UnknownVal.
        if (InitVal.isUnknown()) {
          QualType Ty = InitEx->getType();
          if (InitEx->isGLValue()) {
            Ty = getContext().getPointerType(Ty);
          }

          InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, LC, Ty,
                                   currentBuilderContext->getCurrentBlockCount());
        }
        B.takeNodes(N);
        ExplodedNodeSet Dst2;
        evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true);
        B.addNodes(Dst2);
      }
    }
    else {
      B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC)));
    }
  }
}
Example #4
0
void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
  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();
  ProgramStateRef state = C.getState();
  SVal sizeV = state->getSVal(SE, C.getLocationContext());

  if (sizeV.isUndef()) {
    reportBug(VLA_Garbage, SE, state, C);
    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 tainted.
  if (state->isTainted(sizeV)) {
    reportBug(VLA_Tainted, SE, nullptr, C);
    return;
  }

  // Check if the size is zero.
  DefinedSVal sizeD = sizeV.castAs<DefinedSVal>();

  ProgramStateRef stateNotZero, stateZero;
  std::tie(stateNotZero, stateZero) = state->assume(sizeD);

  if (stateZero && !stateNotZero) {
    reportBug(VLA_Zero, SE, stateZero, C);
    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 =
      svalBuilder.evalCast(sizeD, SizeTy, SE->getType()).castAs<NonLoc>();

  // 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, EleSizeVal.castAs<NonLoc>(), SizeTy);

  // Finally, assume that the array's extent matches the given size.
  const LocationContext *LC = C.getLocationContext();
  DefinedOrUnknownSVal Extent =
    state->getRegion(VD, LC)->getExtent(svalBuilder);
  DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>();
  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);
}
// handle assigning to an iterator
ProgramStateRef IteratorsChecker::handleAssign(ProgramStateRef state,
    const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const {
  // Assume unknown until we find something definite.
  state = state->set<IteratorState>(MR, RefState::getUnknown());
  if (const MaterializeTemporaryExpr *M 
                                    = dyn_cast<MaterializeTemporaryExpr>(rexp))
    rexp = M->GetTemporaryExpr();
  if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(rexp))
    rexp = ICE->getSubExpr();
  // Need to handle three cases: MemberCall, copy, copy with addition.
  if (const CallExpr *CE = dyn_cast<CallExpr>(rexp)) {
    // Handle MemberCall.
    if (const MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee())) {
      const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase());
      if (!DRE)
        return state;
      // Verify that the type is std::vector<T>.
      if (getTemplateKind(DRE->getType()) != VectorKind)
          return state;
      // Now get the MemRegion associated with the instance.
      const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
      if (!VD)
        return state;
      const MemRegion *IMR = state->getRegion(VD, LC);
      if (!IMR)
        return state;
      // Finally, see if it is one of the calls that will create
      // a valid iterator and mark it if so, else mark as Unknown.
      StringRef mName = ME->getMemberDecl()->getName();
      
      if (llvm::StringSwitch<bool>(mName)        
          .Cases("begin", "insert", "erase", true).Default(false)) {
        return state->set<IteratorState>(MR, RefState::getBeginValid(IMR));
      }
      if (mName == "end")
        return state->set<IteratorState>(MR, RefState::getEndValid(IMR));

      return state->set<IteratorState>(MR, RefState::getUnknown());
    }
  }
  // Handle straight copy from another iterator.
  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(rexp)) {
    if (getTemplateKind(DRE->getType()) != VectorIteratorKind)
      return state;
    // Now get the MemRegion associated with the instance.
    const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
    if (!VD)
      return state;
    const MemRegion *IMR = state->getRegion(VD, LC);
    if (!IMR)
      return state;
    // Get the RefState of the iterator being copied.
    const RefState *RS = state->get<IteratorState>(IMR);
    if (!RS)
      return state;
    // Use it to set the state of the LValue.
    return state->set<IteratorState>(MR, *RS);
  }
  // If we have operator+ or operator- ...
  if (const CXXOperatorCallExpr *OCE = dyn_cast<CXXOperatorCallExpr>(rexp)) {
    OverloadedOperatorKind Kind = OCE->getOperator();
    if (Kind == OO_Plus || Kind == OO_Minus) {
      // Check left side of tree for a valid value.
      state = handleAssign( state, MR, OCE->getArg(0), LC);
      const RefState *RS = state->get<IteratorState>(MR);
      // If found, return it.
      if (!RS->isUnknown())
        return state;
      // Otherwise return what we find in the right side.
      return handleAssign(state, MR, OCE->getArg(1), LC);
    }
  }
  // Fall through if nothing matched.
  return state;
}