r301384 - [analyzer] Teach the MallocChecker about Glib API for two arguments

Leslie Zhai via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 25 22:33:14 PDT 2017


Author: xiangzhai
Date: Wed Apr 26 00:33:14 2017
New Revision: 301384

URL: http://llvm.org/viewvc/llvm-project?rev=301384&view=rev
Log:
[analyzer] Teach the MallocChecker about Glib API for two arguments

Reviewers: zaks.anna, NoQ, danielmarjamaki

Reviewed By: zaks.anna, NoQ, danielmarjamaki

Subscribers: cfe-commits, kalev, pwithnall

Differential Revision: https://reviews.llvm.org/D30771

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
    cfe/trunk/test/Analysis/gmalloc.c

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=301384&r1=301383&r2=301384&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Wed Apr 26 00:33:14 2017
@@ -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(A
   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
           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> MallocCh
   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
       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
         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::ReportUseZeroAllocat
   }
 }
 
-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::ReallocMe
   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::ReallocMe
 
   // 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::ReallocMe
   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
     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);
 }

Modified: cfe/trunk/test/Analysis/gmalloc.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/gmalloc.c?rev=301384&r1=301383&r2=301384&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/gmalloc.c (original)
+++ cfe/trunk/test/Analysis/gmalloc.c Wed Apr 26 00:33:14 2017
@@ -13,6 +13,12 @@ gpointer g_realloc(gpointer mem, gsize n
 gpointer g_try_malloc(gsize n_bytes);
 gpointer g_try_malloc0(gsize n_bytes);
 gpointer g_try_realloc(gpointer mem, gsize n_bytes);
+gpointer g_malloc_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_malloc0_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_realloc_n(gpointer mem, gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_malloc_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_malloc0_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_realloc_n(gpointer mem, gsize n_blocks, gsize n_block_bytes);
 void g_free(gpointer mem);
 gpointer g_memdup(gconstpointer mem, guint byte_size);
 
@@ -25,6 +31,12 @@ void f1() {
   gpointer g3 = g_try_malloc(n_bytes);
   gpointer g4 = g_try_malloc0(n_bytes);
   g3 = g_try_realloc(g3, n_bytes * 2);
+  gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+  gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+  g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+  gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+  gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+  g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char));
 
   g_free(g1);
   g_free(g2);
@@ -38,6 +50,12 @@ void f2() {
   gpointer g3 = g_try_malloc(n_bytes);
   gpointer g4 = g_try_malloc0(n_bytes);
   g3 = g_try_realloc(g3, n_bytes * 2);
+  gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+  gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+  g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+  gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+  gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+  g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char));
 
   g_free(g1);
   g_free(g2);
@@ -52,8 +70,100 @@ void f3() {
   gpointer g3 = g_try_malloc(n_bytes);
   gpointer g4 = g_try_malloc0(n_bytes);
   g3 = g_try_realloc(g3, n_bytes * 2); // expected-warning{{Potential leak of memory pointed to by 'g4'}}
+  gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+  gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+  g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+  gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g5'}}
+  gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+  g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+  g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+  g_free(g2);
+  g_free(g3);
+}
+
+void f4() {
+  gpointer g1 = g_malloc(n_bytes);
+  gpointer g2 = g_malloc0(n_bytes);
+  g1 = g_realloc(g1, n_bytes * 2);
+  gpointer g3 = g_try_malloc(n_bytes);
+  gpointer g4 = g_try_malloc0(n_bytes);
+  g3 = g_try_realloc(g3, n_bytes * 2);
+  gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+  gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+  g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+  gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g5'}}
+  gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+  g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+  g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+  g_free(g2);
+  g_free(g3);
+  g_free(g4);
+}
+
+void f5() {
+  gpointer g1 = g_malloc(n_bytes);
+  gpointer g2 = g_malloc0(n_bytes);
+  g1 = g_realloc(g1, n_bytes * 2);
+  gpointer g3 = g_try_malloc(n_bytes);
+  gpointer g4 = g_try_malloc0(n_bytes);
+  g3 = g_try_realloc(g3, n_bytes * 2);
+  gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+  gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+  g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+  gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+  gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+  g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+  g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+  g_free(g2);
+  g_free(g3);
+  g_free(g4);
+  g_free(g5);
+}
+
+void f6() {
+  gpointer g1 = g_malloc(n_bytes);
+  gpointer g2 = g_malloc0(n_bytes);
+  g1 = g_realloc(g1, n_bytes * 2);
+  gpointer g3 = g_try_malloc(n_bytes);
+  gpointer g4 = g_try_malloc0(n_bytes);
+  g3 = g_try_realloc(g3, n_bytes * 2);
+  gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+  gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+  g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+  gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+  gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+  g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+  g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+  g_free(g2);
+  g_free(g3);
+  g_free(g4);
+  g_free(g5);
+  g_free(g6);
+}
+
+void f7() {
+  gpointer g1 = g_malloc(n_bytes);
+  gpointer g2 = g_malloc0(n_bytes);
+  g1 = g_realloc(g1, n_bytes * 2);
+  gpointer g3 = g_try_malloc(n_bytes);
+  gpointer g4 = g_try_malloc0(n_bytes);
+  g3 = g_try_realloc(g3, n_bytes * 2);
+  gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+  gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+  g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+  gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+  gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+  g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
 
   g_free(g1);
   g_free(g2);
   g_free(g3);
+  g_free(g4);
+  g_free(g5);
+  g_free(g6);
+  g_free(g7);
 }




More information about the cfe-commits mailing list