diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/MallocChecker.cpp')
| -rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 102 | 
1 files changed, 74 insertions, 28 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 6e9b7fefa3d0..5730517289bb 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -177,7 +177,10 @@ public:          II_wcsdup(nullptr), II_win_wcsdup(nullptr), II_g_malloc(nullptr),          II_g_malloc0(nullptr), II_g_realloc(nullptr), II_g_try_malloc(nullptr),           II_g_try_malloc0(nullptr), II_g_try_realloc(nullptr),  -        II_g_free(nullptr), II_g_memdup(nullptr) {} +        II_g_free(nullptr), II_g_memdup(nullptr), II_g_malloc_n(nullptr),  +        II_g_malloc0_n(nullptr), II_g_realloc_n(nullptr),  +        II_g_try_malloc_n(nullptr), II_g_try_malloc0_n(nullptr),  +        II_g_try_realloc_n(nullptr) {}    /// In pessimistic mode, the checker assumes that it does not know which    /// functions might free the memory. @@ -241,7 +244,10 @@ private:                           *II_if_nameindex, *II_if_freenameindex, *II_wcsdup,                           *II_win_wcsdup, *II_g_malloc, *II_g_malloc0,                            *II_g_realloc, *II_g_try_malloc, *II_g_try_malloc0,  -                         *II_g_try_realloc, *II_g_free, *II_g_memdup; +                         *II_g_try_realloc, *II_g_free, *II_g_memdup,  +                         *II_g_malloc_n, *II_g_malloc0_n, *II_g_realloc_n,  +                         *II_g_try_malloc_n, *II_g_try_malloc0_n,  +                         *II_g_try_realloc_n;    mutable Optional<uint64_t> KernelZeroFlagVal;    void initIdentifierInfo(ASTContext &C) const; @@ -321,9 +327,12 @@ private:                               bool &ReleasedAllocated,                               bool ReturnsNullOnFailure = false) const; -  ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE, -                             bool FreesMemOnFailure, -                             ProgramStateRef State) const; +  ProgramStateRef ReallocMemAux(CheckerContext &C, const CallExpr *CE, +                                bool FreesMemOnFailure, +                                ProgramStateRef State,  +                                bool SuffixWithN = false) const; +  static SVal evalMulForBufferSize(CheckerContext &C, const Expr *Blocks, +                                   const Expr *BlockBytes);    static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,                                     ProgramStateRef State); @@ -569,6 +578,12 @@ void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {    II_g_try_realloc = &Ctx.Idents.get("g_try_realloc");    II_g_free = &Ctx.Idents.get("g_free");    II_g_memdup = &Ctx.Idents.get("g_memdup"); +  II_g_malloc_n = &Ctx.Idents.get("g_malloc_n"); +  II_g_malloc0_n = &Ctx.Idents.get("g_malloc0_n"); +  II_g_realloc_n = &Ctx.Idents.get("g_realloc_n"); +  II_g_try_malloc_n = &Ctx.Idents.get("g_try_malloc_n"); +  II_g_try_malloc0_n = &Ctx.Idents.get("g_try_malloc0_n"); +  II_g_try_realloc_n = &Ctx.Idents.get("g_try_realloc_n");  }  bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const { @@ -617,7 +632,10 @@ bool MallocChecker::isCMemFunction(const FunctionDecl *FD,            FunI == II_g_malloc || FunI == II_g_malloc0 ||             FunI == II_g_realloc || FunI == II_g_try_malloc ||             FunI == II_g_try_malloc0 || FunI == II_g_try_realloc || -          FunI == II_g_memdup) +          FunI == II_g_memdup || FunI == II_g_malloc_n ||  +          FunI == II_g_malloc0_n || FunI == II_g_realloc_n ||  +          FunI == II_g_try_malloc_n || FunI == II_g_try_malloc0_n ||  +          FunI == II_g_try_realloc_n)          return true;      } @@ -767,6 +785,17 @@ llvm::Optional<ProgramStateRef> MallocChecker::performKernelMalloc(    return None;  } +SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks, +                                         const Expr *BlockBytes) { +  SValBuilder &SB = C.getSValBuilder(); +  SVal BlocksVal = C.getSVal(Blocks); +  SVal BlockBytesVal = C.getSVal(BlockBytes); +  ProgramStateRef State = C.getState(); +  SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal, +                                SB.getContext().getSizeType()); +  return TotalSize; +} +  void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {    if (C.wasInlined)      return; @@ -813,10 +842,10 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {        State = ProcessZeroAllocation(C, CE, 0, State);      } else if (FunI == II_realloc || FunI == II_g_realloc ||                  FunI == II_g_try_realloc) { -      State = ReallocMem(C, CE, false, State); +      State = ReallocMemAux(C, CE, false, State);        State = ProcessZeroAllocation(C, CE, 1, State);      } else if (FunI == II_reallocf) { -      State = ReallocMem(C, CE, true, State); +      State = ReallocMemAux(C, CE, true, State);        State = ProcessZeroAllocation(C, CE, 1, State);      } else if (FunI == II_calloc) {        State = CallocMem(C, CE, State); @@ -874,6 +903,25 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {          return;        State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State);        State = ProcessZeroAllocation(C, CE, 1, State); +    } else if (FunI == II_g_malloc_n || FunI == II_g_try_malloc_n ||  +               FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) { +      if (CE->getNumArgs() < 2) +        return; +      SVal Init = UndefinedVal(); +      if (FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) { +        SValBuilder &SB = C.getSValBuilder(); +        Init = SB.makeZeroVal(SB.getContext().CharTy); +      } +      SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1)); +      State = MallocMemAux(C, CE, TotalSize, Init, State); +      State = ProcessZeroAllocation(C, CE, 0, State); +      State = ProcessZeroAllocation(C, CE, 1, State); +    } else if (FunI == II_g_realloc_n || FunI == II_g_try_realloc_n) { +      if (CE->getNumArgs() < 3) +        return; +      State = ReallocMemAux(C, CE, false, State, true); +      State = ProcessZeroAllocation(C, CE, 1, State); +      State = ProcessZeroAllocation(C, CE, 2, State);      }    } @@ -1976,14 +2024,17 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C,    }  } -ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, -                                          const CallExpr *CE, -                                          bool FreesOnFail, -                                          ProgramStateRef State) const { +ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C, +                                             const CallExpr *CE, +                                             bool FreesOnFail, +                                             ProgramStateRef State,  +                                             bool SuffixWithN) const {    if (!State)      return nullptr; -  if (CE->getNumArgs() < 2) +  if (SuffixWithN && CE->getNumArgs() < 3) +    return nullptr; +  else if (CE->getNumArgs() < 2)      return nullptr;    const Expr *arg0Expr = CE->getArg(0); @@ -1998,20 +2049,19 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,    DefinedOrUnknownSVal PtrEQ =      svalBuilder.evalEQ(State, arg0Val, svalBuilder.makeNull()); -  // Get the size argument. If there is no size arg then give up. +  // Get the size argument.    const Expr *Arg1 = CE->getArg(1); -  if (!Arg1) -    return nullptr;    // Get the value of the size argument. -  SVal Arg1ValG = State->getSVal(Arg1, LCtx); -  if (!Arg1ValG.getAs<DefinedOrUnknownSVal>()) +  SVal TotalSize = State->getSVal(Arg1, LCtx); +  if (SuffixWithN) +    TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2)); +  if (!TotalSize.getAs<DefinedOrUnknownSVal>())      return nullptr; -  DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>();    // Compare the size argument to 0.    DefinedOrUnknownSVal SizeZero = -    svalBuilder.evalEQ(State, Arg1Val, +    svalBuilder.evalEQ(State, TotalSize.castAs<DefinedOrUnknownSVal>(),                         svalBuilder.makeIntValWithPtrWidth(0, false));    ProgramStateRef StatePtrIsNull, StatePtrNotNull; @@ -2025,8 +2075,8 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,    // If the ptr is NULL and the size is not 0, the call is equivalent to    // malloc(size). -  if ( PrtIsNull && !SizeIsZero) { -    ProgramStateRef stateMalloc = MallocMemAux(C, CE, CE->getArg(1), +  if (PrtIsNull && !SizeIsZero) { +    ProgramStateRef stateMalloc = MallocMemAux(C, CE, TotalSize,                                                 UndefinedVal(), StatePtrIsNull);      return stateMalloc;    } @@ -2059,7 +2109,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,    if (ProgramStateRef stateFree =          FreeMemAux(C, CE, State, 0, false, ReleasedAllocated)) { -    ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1), +    ProgramStateRef stateRealloc = MallocMemAux(C, CE, TotalSize,                                                  UnknownVal(), stateFree);      if (!stateRealloc)        return nullptr; @@ -2090,12 +2140,8 @@ ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,      return nullptr;    SValBuilder &svalBuilder = C.getSValBuilder(); -  const LocationContext *LCtx = C.getLocationContext(); -  SVal count = State->getSVal(CE->getArg(0), LCtx); -  SVal elementSize = State->getSVal(CE->getArg(1), LCtx); -  SVal TotalSize = svalBuilder.evalBinOp(State, BO_Mul, count, elementSize, -                                        svalBuilder.getContext().getSizeType());    SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy); +  SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));    return MallocMemAux(C, CE, TotalSize, zeroVal, State);  }  | 
