Example #1
0
void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
  if (!DS->isSingleDecl())
    return;
  
  const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
  if (!VD)
    return;
  
  const VariableArrayType *VLA
    = C.getASTContext().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;
  }
  
  // Check if the size is zero.
  DefinedOrUnknownSVal sizeD = cast<DefinedOrUnknownSVal>(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.
  C.addTransition(stateNotZero);
}
void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C,
                                            const ReturnStmt *RS) {
 
  const Expr *RetE = RS->getRetValue();
  if (!RetE)
    return;
  
  if (!C.getState()->getSVal(RetE).isUndef())
    return;
  
  ExplodedNode *N = C.GenerateSink();

  if (!N)
    return;
  
  if (!BT)
    BT = new BuiltinBug("Garbage return value",
                        "Undefined or garbage value returned to caller");
    
  EnhancedBugReport *report = 
    new EnhancedBugReport(*BT, BT->getDescription(), N);

  report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, RetE);

  C.EmitReport(report);
}
Example #3
0
void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
                                                   const ReturnStmt *RS) {
  const GRState *state = C.getState();

  const Expr *RetE = RS->getRetValue();
  if (!RetE)
    return;
 
  SVal V = state->getSVal(RetE);
  const MemRegion *R = V.getAsRegion();
  if (!R)
    return;

  R = R->StripCasts();
  if (!R)
    return;

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

  DefinedOrUnknownSVal &Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());

  // FIXME: All of this out-of-bounds checking should eventually be refactored
  // into a common place.

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

  const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true);
  const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false);
  if (StOutBound && !StInBound) {
    ExplodedNode *N = C.GenerateSink(StOutBound);

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

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

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

    report->addRange(RetE->getSourceRange());
    C.EmitReport(report);
  }
}
Example #4
0
void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) {
  const Expr *E = CE->getSubExpr();
  ASTContext &Ctx = C.getASTContext();
  QualType ToTy = Ctx.getCanonicalType(CE->getType());
  PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());

  if (!ToPTy)
    return;

  QualType ToPointeeTy = ToPTy->getPointeeType();

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

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

  ValueManager &ValMgr = C.getValueManager();
  SVal Extent = SR->getExtent(ValMgr);

  SValuator &SVator = ValMgr.getSValuator();
  const llvm::APSInt *ExtentInt = SVator.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) {
    if (ExplodedNode *N = C.GenerateSink()) {
      if (!BT)
        BT = new BuiltinBug("Cast region with wrong size.",
                            "Cast a region whose size is not a multiple of the"
                            " destination type size.");
      RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
      R->addRange(CE->getSourceRange());
      C.EmitReport(R);
    }
  }
}
void 
UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C, 
                                                const ArraySubscriptExpr *A) {
  if (C.getState()->getSVal(A->getIdx()).isUndef()) {
    if (ExplodedNode *N = C.GenerateSink()) {
      if (!BT)
        BT = new BuiltinBug("Array subscript is undefined");

      // Generate a report for this bug.
      EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
      R->addRange(A->getIdx()->getSourceRange());
      R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 
                           A->getIdx());
      C.EmitReport(R);
    }
  }
}
Example #6
0
void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
                                            const BinaryOperator *B) {
  BinaryOperator::Opcode Op = B->getOpcode();
  if (Op != BO_Div &&
      Op != BO_Rem &&
      Op != BO_DivAssign &&
      Op != BO_RemAssign)
    return;

  if (!B->getRHS()->getType()->isIntegerType() ||
      !B->getRHS()->getType()->isScalarType())
    return;

  SVal Denom = C.getState()->getSVal(B->getRHS());
  const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);

  // Divide-by-undefined handled in the generic checking for uses of
  // undefined values.
  if (!DV)
    return;

  // Check for divide by zero.
  ConstraintManager &CM = C.getConstraintManager();
  const GRState *stateNotZero, *stateZero;
  llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV);

  if (stateZero && !stateNotZero) {
    if (ExplodedNode *N = C.GenerateSink(stateZero)) {
      if (!BT)
        BT = new BuiltinBug("Division by zero");

      EnhancedBugReport *R = 
        new EnhancedBugReport(*BT, BT->getDescription(), N);

      R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
                           bugreporter::GetDenomExpr(N));

      C.EmitReport(R);
    }
    return;
  }

  // If we get here, then the denom should not be zero. We abandon the implicit
  // zero denom case for now.
  C.addTransition(stateNotZero);
}
Example #7
0
static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
                              BugType *&BT, const IdentifierInfo *FI) {

  if (!BT) {
    llvm::SmallString<128> S;
    llvm::raw_svector_ostream os(S);
    os << "Improper use of '" << FI->getName() << '\'';
    BT = new BugType(os.str(), "Mac OS X API");
  }

  if (CE->getNumArgs() < 1)
    return;

  // Check if the first argument is stack allocated.  If so, issue a warning
  // because that's likely to be bad news.
  const GRState *state = C.getState();
  const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
  if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
    return;

  ExplodedNode *N = C.GenerateSink(state);
  if (!N)
    return;

  llvm::SmallString<256> S;
  llvm::raw_svector_ostream os(S);
  os << "Call to '" << FI->getName() << "' uses";
  if (const VarRegion *VR = dyn_cast<VarRegion>(R))
    os << " the local variable '" << VR->getDecl()->getName() << '\'';
  else
    os << " stack allocated memory";
  os << " for the predicate value.  Using such transient memory for "
        "the predicate is potentially dangerous.";
  if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
    os << "  Perhaps you intended to declare the variable as 'static'?";

  EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
  report->addRange(CE->getArg(0)->getSourceRange());
  C.EmitReport(report);
}
Example #8
0
void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
                                       SVal l) {
  // Check for dereference of an undefined value.
  if (l.isUndef()) {
    if (ExplodedNode *N = C.GenerateSink()) {
      if (!BT_undef)
        BT_undef = new BuiltinBug("Dereference of undefined pointer value");

      EnhancedBugReport *report =
        new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
                                bugreporter::GetDerefExpr(N));
      C.EmitReport(report);
    }
    return;
  }

  DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);

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

  const GRState *state = C.getState();
  const GRState *notNullState, *nullState;
  llvm::tie(notNullState, nullState) = state->Assume(location);

  // The explicit NULL case.
  if (nullState) {
    if (!notNullState) {
      // Generate an error node.
      ExplodedNode *N = C.GenerateSink(nullState);
      if (!N)
        return;

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

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

      switch (S->getStmtClass()) {
        case Stmt::UnaryOperatorClass: {
          const UnaryOperator *U = cast<UnaryOperator>(S);
          const Expr *SU = U->getSubExpr()->IgnoreParens();
          if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) {
            if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
              llvm::raw_svector_ostream os(buf);
              os << "Dereference of null pointer (loaded from variable '"
                 << VD->getName() << "')";
              Ranges.push_back(DR->getSourceRange());
            }
          }
          break;
        }
        case Stmt::MemberExprClass: {
          const MemberExpr *M = cast<MemberExpr>(S);
          if (M->isArrow())
            if (DeclRefExpr *DR =
                dyn_cast<DeclRefExpr>(M->getBase()->IgnoreParenCasts())) {
              if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
                llvm::raw_svector_ostream os(buf);
                os << "Field access results in a dereference of a null pointer "
                      "(loaded from variable '" << VD->getName() << "')";
                Ranges.push_back(M->getBase()->getSourceRange());
              }
            }
          break;
        }
        default:
          break;
      }

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

      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
                                bugreporter::GetDerefExpr(N));

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

      C.EmitReport(report);
      return;
    }
    else {
      // Otherwise, we have the case where the location could either be
      // null or not-null.  Record the error node as an "implicit" null
      // dereference.
      if (ExplodedNode *N = C.GenerateSink(nullState))
        ImplicitNullDerefNodes.push_back(N);
    }
  }

  // From this point forward, we know that the location is not null.
  C.addTransition(notNullState);
}