xiangzhai updated this revision to Diff 96344.
xiangzhai added a comment.

Hi Artem,

Because `memcpy` checked NULL pointer dereference for `src`:

  state = checkNonNull(C, state, Source, srcVal);
  ...

so such testcase can not point out my fault:

  void f15 () {                                                                 
     
    int *x = malloc(sizeof(int));                                               
     
    memcpy(x, 0, sizeof(int)); // expected-warning {{Null pointer argument in 
call to memory copy function}}
    int n = 1 / *x;                                                             
     
    free(x);                                                                    
     
  }

And I have no idea how to copy `RetVal` to Mem `s`:

  if (StateSameSize) {                                                          
  
        SVal ConstVal = State->getSVal(Const, LCtx);                            
      
        State = State->BindExpr(CE, LCtx, RetVal);                              
      
        // Actually bind the second argument value to the buffer.               
      
        State = State->bindDefault(RetVal, ConstVal, LCtx);                     
      
        // FIXME: Copy to Mem                                                   
      
        const MemRegion *MR = RetVal.getAsRegion();                             
      
        if (!MR)                                                                
      
          return;                                                               
      
        MR = MR->StripCasts();                                                  
      
        if (const TypedValueRegion *TVR = MR->getAs<TypedValueRegion>()) {      
      
          MemVal = SB.makeLazyCompoundVal(StoreRef(State->getStore(),           
      
                      State->getStateManager().getStoreManager()), TVR);        
      
          State = State->BindExpr(CE, LCtx, MemVal);                            
      
        }                                                                       
      
        C.addTransition(State);                                                 
      
      }

Please give me some advice, thanks a lot!

Regards,
Leslie Zhai


Repository:
  rL LLVM

https://reviews.llvm.org/D31868

Files:
  lib/StaticAnalyzer/Checkers/CStringChecker.cpp
  test/Analysis/null-deref-ps-region.c

Index: test/Analysis/null-deref-ps-region.c
===================================================================
--- test/Analysis/null-deref-ps-region.c
+++ test/Analysis/null-deref-ps-region.c
@@ -1,6 +1,11 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -std=gnu99 -analyzer-store=region -verify %s
-// expected-no-diagnostics
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,unix,alpha.unix -std=gnu99 -analyzer-store=region -verify %s
 
+#include "Inputs/system-header-simulator.h"
+
+typedef __typeof(sizeof(int)) size_t;
+void *memset(void *__s, int __c, size_t __n);
+void *malloc(size_t __size);
+void free(void *__ptr);
 
 // The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may
 // also be live roots.
@@ -13,3 +18,69 @@
     i = *p; // no-warning
   }
 }
+
+void f15 () {
+  int *x = malloc(sizeof(int));
+  memcpy(x, 0, sizeof(int)); // expected-warning {{Null pointer argument in call to memory copy function}}
+  int n = 1 / *x;
+  free(x);
+}
+
+void foo() {
+  int *x = malloc(sizeof(int));
+  int *r = memset(x, 0, sizeof(int));
+  int n = 1 / *r; // expected-warning {{Division by zero}}
+  free(x);
+}
+
+void foo2() {
+  int *x = malloc(sizeof(int));
+  memset(x, 0, sizeof(int));
+  int n = 1 / *x;
+  free(x);
+}
+
+void bar() {
+  int *x = malloc(sizeof(int));
+  memset(x, 0, 1);
+  int n = 1 / *x; // no-warning
+  free(x);
+}
+
+void f531() {
+  int *x = 0;
+  memset(x, 0, 1); // expected-warning {{Null pointer argument in call to memory set function}}
+}
+
+void f61() {
+  char buf[13];
+  memset(buf, 0, 1); // no-warning
+}
+
+void f611() {
+  char *buf = (char *)malloc(13);
+  memset(buf, 0, 1); // no-warning
+  free(buf);
+}
+
+void f66() {
+  char buf[1];
+  memset(buf, 0, 1024); // expected-warning {{Memory set function accesses out-of-bound array element}}
+}
+
+void f666() {
+  char *buf = (char *)malloc(1);
+  memset(buf, 0, 1024); // expected-warning {{Memory set function accesses out-of-bound array element}}
+  free(buf);
+}
+
+void f77() {
+  char buf[1];
+  memset(buf, 0, sizeof(buf)); // no-warning
+}
+
+void f777() {
+  char *buf = (char *)malloc(1);
+  memset(buf, 0, 1); // no-warning
+  free(buf);
+}
Index: lib/StaticAnalyzer/Checkers/CStringChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -120,6 +120,7 @@
   void evalStdCopy(CheckerContext &C, const CallExpr *CE) const;
   void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const;
   void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const;
+  void evalMemset(CheckerContext &C, const CallExpr *CE) const;
 
   // Utility methods
   std::pair<ProgramStateRef , ProgramStateRef >
@@ -1999,6 +2000,89 @@
   C.addTransition(State);
 }
 
+void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const {
+  if (CE->getNumArgs() != 3)
+    return;
+
+  CurrentFunctionDescription = "memory set function";
+
+  const Expr *Mem = CE->getArg(0);
+  const Expr *Const = CE->getArg(1);
+  const Expr *Size = CE->getArg(2);
+  ProgramStateRef State = C.getState();
+
+  // See if the size argument is zero.
+  const LocationContext *LCtx = C.getLocationContext();
+  SVal SizeVal = State->getSVal(Size, LCtx);
+  QualType SizeTy = Size->getType();
+
+  ProgramStateRef StateZeroSize, StateNonZeroSize;
+  std::tie(StateZeroSize, StateNonZeroSize) =
+    assumeZero(C, State, SizeVal, SizeTy);
+
+  // Get the value of the memory area.
+  SVal MemVal = State->getSVal(Mem, LCtx);
+
+  // If the size is zero, there won't be any actual memory access, so
+  // just bind the return value to the Mem buffer and return.
+  if (StateZeroSize && !StateNonZeroSize) {
+    StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, MemVal);
+    C.addTransition(StateZeroSize);
+    return;
+  }
+
+  if (!StateNonZeroSize)
+    return;
+
+  // Ensure the memory area is not null.
+  // If it is NULL there will be a NULL pointer dereference.
+  State = checkNonNull(C, StateNonZeroSize, Mem, MemVal);
+  if (!State)
+    return;
+
+  SValBuilder &SB = C.getSValBuilder();
+  // Check the region's extent is equal to the Size parameter.
+  SVal RetVal = SB.getConjuredHeapSymbolVal(CE, LCtx, C.blockCount());
+  const SymbolicRegion *SR =
+      dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
+  if (!SR)
+    return;
+  if (Optional<DefinedOrUnknownSVal> DefinedSize =
+          SizeVal.getAs<DefinedOrUnknownSVal>()) {
+    DefinedOrUnknownSVal Extent = SR->getExtent(SB);
+    ProgramStateRef StateSameSize, StateNotSameSize;
+    std::tie(StateSameSize, StateNotSameSize) =
+        State->assume(SB.evalEQ(State, Extent, *DefinedSize));
+    if (StateNotSameSize) {
+      State = CheckBufferAccess(C, State, Size, Mem);
+      if (!State)
+        return;
+      State = InvalidateBuffer(C, State, Mem, C.getSVal(Mem),
+                               /*IsSourceBuffer*/false, Size);
+      if (!State)
+        return;
+    }
+
+    if (StateSameSize) {
+      SVal ConstVal = State->getSVal(Const, LCtx);
+      State = State->BindExpr(CE, LCtx, RetVal);
+      // Actually bind the second argument value to the buffer.
+      State = State->bindDefault(RetVal, ConstVal, LCtx);
+      // FIXME: Copy to Mem
+      const MemRegion *MR = RetVal.getAsRegion();
+      if (!MR)
+        return;
+      MR = MR->StripCasts();
+      if (const TypedValueRegion *TVR = MR->getAs<TypedValueRegion>()) {
+        MemVal = SB.makeLazyCompoundVal(StoreRef(State->getStore(),
+                    State->getStateManager().getStoreManager()), TVR);
+        State = State->BindExpr(CE, LCtx, MemVal);
+      }
+      C.addTransition(State);
+    }
+  }
+}
+
 static bool isCPPStdLibraryFunction(const FunctionDecl *FD, StringRef Name) {
   IdentifierInfo *II = FD->getIdentifier();
   if (!II)
@@ -2032,6 +2116,8 @@
     evalFunction =  &CStringChecker::evalMemcmp;
   else if (C.isCLibraryFunction(FDecl, "memmove"))
     evalFunction =  &CStringChecker::evalMemmove;
+  else if (C.isCLibraryFunction(FDecl, "memset"))
+    evalFunction =  &CStringChecker::evalMemset;
   else if (C.isCLibraryFunction(FDecl, "strcpy"))
     evalFunction =  &CStringChecker::evalStrcpy;
   else if (C.isCLibraryFunction(FDecl, "strncpy"))
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to