ariccio created this revision.
ariccio added reviewers: zaks.anna, dcoughlin, aaron.ballman.
ariccio added a subscriber: cfe-commits.
As discussed...
http://reviews.llvm.org/D18073
Files:
llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
llvm/tools/clang/test/Analysis/malloc.c
Index: llvm/tools/clang/test/Analysis/malloc.c
===================================================================
--- llvm/tools/clang/test/Analysis/malloc.c
+++ llvm/tools/clang/test/Analysis/malloc.c
@@ -31,12 +31,50 @@
wchar_t *wcsdup(const wchar_t *s);
char *strndup(const char *s, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
+char *tempnam(const char *dir, const char *pfx);
+
// Windows variants
char *_strdup(const char *strSource);
wchar_t *_wcsdup(const wchar_t *strSource);
+unsigned char *_mbsdup(const unsigned char *strSource);
+
void *_alloca(size_t size);
+char *_tempnam(const char *dir, const char *prefix);
+wchar_t *_wtempnam(const wchar_t *dir, const wchar_t *prefix);
+
+
+void *_calloc_dbg(size_t num, size_t size, int blockType,
+ const char *filename, int linenumber);
+
+char *_strdup_dbg(const char *strSource, int blockType,
+ const char *filename, int linenumber);
+
+wchar_t *_wcsdup_dbg(const wchar_t *strSource, int blockType,
+ const char *filename, int linenumber);
+
+unsigned char *_mbsdup_dbg(const unsigned char *strSource, int blockType,
+ const char *filename, int linenumber);
+
+char *_tempnam_dbg(const char *dir, const char *prefix, int blockType,
+ const char *filename, int linenumber);
+
+wchar_t *_wtempnam_dbg(const wchar_t *dir, const wchar_t *prefix,
+ int blockType, const char *filename, int linenumber);
+
+
+
+// Very frequently used debug versions
+void _free_dbg(void *userData, int blockType);
+void _malloc_dbg(size_t size, int blockType, const char *filename,
+ int linenumber);
+
+void *_realloc_dbg(void *userData, size_t newSize,
+ int blockType, const char *filename, int linenumber);
+
+
+
void myfoo(int *p);
void myfooint(int p);
char *fooRetPtr();
@@ -291,25 +329,37 @@
}
void CheckUseZeroAllocated6() {
+ int *p = _calloc_dbg(0, 2, 0, __FILE__, __LINE__);
+ *p = 1; // expected-warning {{Use of zero-allocated memory}}
+ free(p);
+}
+
+void CheckUseZeroAllocated7() {
int *p = calloc(2, 0);
*p = 1; // expected-warning {{Use of zero-allocated memory}}
free(p);
}
-void CheckUseZeroAllocated7() {
+void CheckUseZeroAllocated8() {
+ int *p = _calloc_dbg(2, 0, 0, __FILE__, __LINE__);
+ *p = 1; // expected-warning {{Use of zero-allocated memory}}
+ free(p);
+}
+
+void CheckUseZeroAllocated9() {
int *p = realloc(0, 0);
*p = 1; // expected-warning {{Use of zero-allocated memory}}
free(p);
}
-void CheckUseZeroAllocated8() {
+void CheckUseZeroAllocated10() {
int *p = malloc(8);
int *q = realloc(p, 0);
*q = 1; // expected-warning {{Use of zero-allocated memory}}
free(q);
}
-void CheckUseZeroAllocated9() {
+void CheckUseZeroAllocated11() {
int *p = realloc(0, 0);
int *q = realloc(p, 0);
*q = 1; // expected-warning {{Use of zero-allocated memory}}
@@ -690,6 +740,12 @@
return; // expected-warning{{Potential leak of memory pointed to by 'buf'}}
}
+// This tests that calloc() buffers need to be freed
+void callocNoFreeDbg () {
+ char *buf = _calloc_dbg(2,2, 0, __FILE__, __LINE__);
+ return; // expected-warning{{Potential leak of memory pointed to by 'buf'}}
+}
+
// These test that calloc() buffers are zeroed by default
char callocZeroesGood () {
char *buf = calloc(2,2);
@@ -700,6 +756,16 @@
return result; // no-warning
}
+// These test that calloc() buffers are zeroed by default
+char callocZeroesGoodDbg () {
+ char *buf = _calloc_dbg(2,2,0, __FILE__, __LINE__);
+ char result = buf[3]; // no-warning
+ if (buf[1] == 0) {
+ free(buf);
+ }
+ return result; // no-warning
+}
+
char callocZeroesBad () {
char *buf = calloc(2,2);
char result = buf[3]; // no-warning
@@ -709,6 +775,15 @@
return result; // expected-warning{{Potential leak of memory pointed to by 'buf'}}
}
+char callocZeroesBadDbg () {
+ char *buf = _calloc_dbg(2,2, 0, __FILE__, __LINE__);
+ char result = buf[3]; // no-warning
+ if (buf[1] != 0) {
+ free(buf); // expected-warning{{never executed}}
+ }
+ return result; // expected-warning{{Potential leak of memory pointed to by 'buf'}}
+}
+
void nullFree() {
int *p = 0;
free(p); // no warning - a nop
@@ -1126,6 +1201,26 @@
s2[validIndex + 1] = 'b';
} // expected-warning {{Potential leak of memory pointed to by}}
+void testWinMbsdup(const unsigned char *s, unsigned validIndex) {
+ unsigned char *s2 = _mbsdup(s);
+ s2[validIndex + 1] = 'b';
+} // expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinMbsdupDbg(const unsigned char *s, unsigned validIndex) {
+ unsigned char *s2 = _mbsdup_dbg(s, 0, __FILE__, __LINE__);
+ s2[validIndex + 1] = 'b';
+} // expected-warning {{Potential leak of memory pointed to by}}
+
+void testStrdupDbg(const char *s, unsigned validIndex) {
+ char *s2 = _strdup_dbg(s, 0, __FILE__, __LINE__);
+ s2[validIndex + 1] = 'b';
+} // expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinWcsdupDbg(const wchar_t *s, unsigned validIndex) {
+ wchar_t *s2 = _wcsdup_dbg(s, 0, __FILE__, __LINE__);
+ s2[validIndex + 1] = 'b';
+} // expected-warning {{Potential leak of memory pointed to by}}
+
int testStrndup(const char *s, unsigned validIndex, unsigned size) {
char *s2 = strndup(s, size);
s2 [validIndex + 1] = 'b';
@@ -1141,6 +1236,12 @@
free(s2);
}
+void testStrdupDbgContentIsDefined(const char *s, unsigned validIndex) {
+ char *s2 = _strdup_dbg(s, 0, __FILE__, __LINE__);
+ char result = s2[1];// no warning
+ free(s2);
+}
+
void testWinStrdupContentIsDefined(const char *s, unsigned validIndex) {
char *s2 = _strdup(s);
char result = s2[1];// no warning
@@ -1159,6 +1260,104 @@
free(s2);
}
+void testWinMbsdupContentIsDefined(const unsigned char *s, unsigned validIndex) {
+ unsigned char *s2 = _mbsdup(s);
+ unsigned char result = s2[1];// no warning
+ free(s2);
+}
+
+void testWinMbsdupDbgContentIsDefined(const unsigned char *s, unsigned validIndex) {
+ unsigned char *s2 = _mbsdup_dbg(s, 0, __FILE__, __LINE__);
+ unsigned char result = s2[1];// no warning
+ free(s2);
+}
+
+void testWinWcsdupDbgContentIsDefined(const wchar_t *s, unsigned validIndex) {
+ wchar_t *s2 = _wcsdup_dbg(s, 0, __FILE__, __LINE__);
+ wchar_t result = s2[1];// no warning
+ free(s2);
+}
+
+void testTempnamLeak(const char* dir, const char* prefix) {
+ char* fileName = tempnam(dir, prefix);
+}// expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinTempnamLeak(const char* dir, const char* prefix) {
+ char* fileName = _tempnam(dir, prefix);
+}// expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinTempnamDbgLeak(const char* dir, const char* prefix) {
+ char* fileName = _tempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+}// expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinWideTempnamLeak(const wchar_t* dir, const wchar_t* prefix) {
+ wchar_t* fileName = _wtempnam(dir, prefix);
+}// expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinWideTempnaDbgmLeak(const wchar_t* dir, const wchar_t* prefix) {
+ wchar_t* fileName = _wtempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+}// expected-warning {{Potential leak of memory pointed to by}}
+
+void testTempnamNoLeak(const char* dir, const char* prefix) {
+ char* fileName = tempnam(dir, prefix);
+ free(fileName);// no warning
+}
+
+void testWinTempnamNoLeak(const char* dir, const char* prefix) {
+ char* fileName = _tempnam(dir, prefix);
+ free(fileName);// no warning
+}
+
+void testWinTempnamDbgNoLeak(const char* dir, const char* prefix) {
+ char* fileName = _tempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+ free(fileName);// no warning
+}
+
+void testWinWideTempnamNoLeak(const wchar_t* dir, const wchar_t* prefix) {
+ wchar_t* fileName = _wtempnam(dir, prefix);
+ free(fileName);// no warning
+}
+
+void testWinWideTempnamDbgNoLeak(const wchar_t* dir, const wchar_t* prefix) {
+ wchar_t* fileName = _wtempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+ free(fileName);// no warning
+}
+
+// What does "ContentIsDefined" refer to?
+void testTempnamNoLeakContentIsDefined(const char* dir, const char* prefix) {
+ char* fileName = tempnam(dir, prefix);
+ char result = fileName[0];// no warning
+ free(fileName);
+}
+
+// What does "ContentIsDefined" refer to?
+void testWinTempnamNoLeakContentIsDefined(const char* dir, const char* prefix) {
+ char* fileName = _tempnam(dir, prefix);
+ char result = fileName[0];// no warning
+ free(fileName);
+}
+
+// What does "ContentIsDefined" refer to?
+void testWinTempnamDbgNoLeakContentIsDefined(const char* dir, const char* prefix) {
+ char* fileName = _tempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+ char result = fileName[0];// no warning
+ free(fileName);
+}
+
+// What does "ContentIsDefined" refer to?
+void testWinWideTempnamNoLeakContentIsDefined(const wchar_t* dir, const wchar_t* prefix) {
+ wchar_t* fileName = _wtempnam(dir, prefix);
+ wchar_t result = fileName[0];// no warning
+ free(fileName);
+}
+
+// What does "ContentIsDefined" refer to?
+void testWinWideTempnamDbgNoLeakContentIsDefined(const wchar_t* dir, const wchar_t* prefix) {
+ wchar_t* fileName = _wtempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+ wchar_t result = fileName[0];// no warning
+ free(fileName);
+}
+
// ----------------------------------------------------------------------------
// Test the system library functions to which the pointer can escape.
// This tests false positive suppression.
@@ -1465,6 +1664,13 @@
xpc_connection_resume(peer);
}
+void fooDbg (xpc_connection_t peer) {
+ int *ctx = _calloc_dbg(1, sizeof(int), 0, __FILE__, __LINE__);
+ xpc_connection_set_context(peer, ctx);
+ xpc_connection_set_finalizer_f(peer, finalize_connection_context);
+ xpc_connection_resume(peer);
+}
+
// Make sure we catch errors when we free in a function which does not allocate memory.
void freeButNoMalloc(int *p, int x){
if (x) {
@@ -1512,14 +1718,33 @@
return strdup(strdup(str)); // expected-warning{{leak}}
}
+char *testLeakWithinDbgReturn(char *str) {
+ return _strdup_dbg(_strdup_dbg(str, 0, __FILE__, __LINE__), 0, __FILE__, __LINE__); // expected-warning{{leak}}
+}
+
char *testWinLeakWithinReturn(char *str) {
return _strdup(_strdup(str)); // expected-warning{{leak}}
}
+wchar_t *testWideLeakWithinReturn(wchar_t *str) {
+ return wcsdup(wcsdup(str)); // expected-warning{{leak}}
+}
+
wchar_t *testWinWideLeakWithinReturn(wchar_t *str) {
return _wcsdup(_wcsdup(str)); // expected-warning{{leak}}
}
+unsigned char *testWinMbsLeakWithinReturn(unsigned char *str) {
+ return _mbsdup(_mbsdup(str)); // expected-warning{{leak}}
+}
+
+unsigned char *testWinMbsDbgLeakWithinReturn(unsigned char *str) {
+ return _mbsdup_dbg(_mbsdup_dbg(str, 0, __FILE__, __LINE__), 0, __FILE__, __LINE__); // expected-warning{{leak}}
+}
+wchar_t *testWinWideDbgLeakWithinReturn(wchar_t *str) {
+ return _wcsdup_dbg(_wcsdup_dbg(str, 0, __FILE__, __LINE__), 0, __FILE__, __LINE__); // expected-warning{{leak}}
+}
+
void passConstPtr(const char * ptr);
void testPassConstPointer() {
Index: llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -174,7 +174,12 @@
II_valloc(nullptr), II_reallocf(nullptr), II_strndup(nullptr),
II_strdup(nullptr), II_win_strdup(nullptr), II_kmalloc(nullptr),
II_if_nameindex(nullptr), II_if_freenameindex(nullptr),
- II_wcsdup(nullptr), II_win_wcsdup(nullptr) {}
+ II_wcsdup(nullptr), II_win_wcsdup(nullptr), II_malloc_dbg(nullptr),
+ II_free_dbg(nullptr), II_realloc_dbg(nullptr), II_calloc_dbg(nullptr),
+ II_wcsdup_dbg(nullptr), II_strdup_dbg(nullptr), II_mbsdup(nullptr),
+ II_mbsdup_dbg(nullptr), II_tempnam(nullptr), II_win_tempnam(nullptr),
+ II_win_tempnam_dbg(nullptr), II_wtempnam(nullptr),
+ II_wtempnam_dbg(nullptr) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
@@ -236,7 +241,11 @@
*II_realloc, *II_calloc, *II_valloc, *II_reallocf,
*II_strndup, *II_strdup, *II_win_strdup, *II_kmalloc,
*II_if_nameindex, *II_if_freenameindex, *II_wcsdup,
- *II_win_wcsdup;
+ *II_win_wcsdup, *II_malloc_dbg, *II_free_dbg,
+ *II_realloc_dbg, *II_calloc_dbg, *II_wcsdup_dbg,
+ *II_strdup_dbg, *II_mbsdup, *II_mbsdup_dbg,
+ *II_tempnam, *II_win_tempnam, *II_win_tempnam_dbg,
+ *II_wtempnam, *II_wtempnam_dbg;
mutable Optional<uint64_t> KernelZeroFlagVal;
void initIdentifierInfo(ASTContext &C) const;
@@ -543,14 +552,29 @@
II_strdup = &Ctx.Idents.get("strdup");
II_strndup = &Ctx.Idents.get("strndup");
II_wcsdup = &Ctx.Idents.get("wcsdup");
+ II_mbsdup = &Ctx.Idents.get("_mbsdup");
II_kmalloc = &Ctx.Idents.get("kmalloc");
II_if_nameindex = &Ctx.Idents.get("if_nameindex");
II_if_freenameindex = &Ctx.Idents.get("if_freenameindex");
//MSVC uses `_`-prefixed instead, so we check for them too.
II_win_strdup = &Ctx.Idents.get("_strdup");
II_win_wcsdup = &Ctx.Idents.get("_wcsdup");
II_win_alloca = &Ctx.Idents.get("_alloca");
+
+ II_malloc_dbg = &Ctx.Idents.get("_malloc_dbg");
+ II_free_dbg = &Ctx.Idents.get("_free_dbg");
+ II_realloc_dbg = &Ctx.Idents.get("_realloc_dbg");
+ II_calloc_dbg = &Ctx.Idents.get("_calloc_dbg");
+ II_wcsdup_dbg = &Ctx.Idents.get("_wcsdup_dbg");
+ II_strdup_dbg = &Ctx.Idents.get("_strdup_dbg");
+ II_mbsdup_dbg = &Ctx.Idents.get("_mbsdup_dbg");
+
+ II_tempnam = &Ctx.Idents.get("tempnam");
+ II_win_tempnam = &Ctx.Idents.get("_tempnam");
+ II_win_tempnam_dbg = &Ctx.Idents.get("_tempnam_dbg");
+ II_wtempnam = &Ctx.Idents.get("_wtempnam");
+ II_wtempnam_dbg = &Ctx.Idents.get("_wtempnam_dbg");
}
bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
@@ -586,15 +610,22 @@
initIdentifierInfo(C);
if (Family == AF_Malloc && CheckFree) {
- if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf)
+ if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf ||
+ FunI == II_free_dbg || FunI == II_realloc_dbg)
return true;
}
if (Family == AF_Malloc && CheckAlloc) {
if (FunI == II_malloc || FunI == II_realloc || FunI == II_reallocf ||
FunI == II_calloc || FunI == II_valloc || FunI == II_strdup ||
FunI == II_win_strdup || FunI == II_strndup || FunI == II_wcsdup ||
- FunI == II_win_wcsdup || FunI == II_kmalloc)
+ FunI == II_win_wcsdup || FunI == II_kmalloc ||
+ FunI == II_malloc_dbg || FunI == II_realloc_dbg ||
+ FunI == II_calloc_dbg || FunI == II_wcsdup_dbg ||
+ FunI == II_strdup_dbg || FunI == II_mbsdup ||
+ FunI == II_mbsdup_dbg || FunI == II_tempnam ||
+ FunI == II_win_tempnam || FunI == II_win_tempnam_dbg ||
+ FunI == II_wtempnam || FunI == II_wtempnam_dbg)
return true;
}
@@ -759,7 +790,7 @@
initIdentifierInfo(C.getASTContext());
IdentifierInfo *FunI = FD->getIdentifier();
- if (FunI == II_malloc) {
+ if (FunI == II_malloc || FunI == II_malloc_dbg) {
if (CE->getNumArgs() < 1)
return;
if (CE->getNumArgs() < 3) {
@@ -786,20 +817,25 @@
return;
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
State = ProcessZeroAllocation(C, CE, 0, State);
- } else if (FunI == II_realloc) {
+ } else if ((FunI == II_realloc) || (FunI == II_realloc_dbg)) {
State = ReallocMem(C, CE, false, State);
State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_reallocf) {
State = ReallocMem(C, CE, true, State);
State = ProcessZeroAllocation(C, CE, 1, State);
- } else if (FunI == II_calloc) {
+ } else if ((FunI == II_calloc) || (FunI == II_calloc_dbg)) {
State = CallocMem(C, CE, State);
State = ProcessZeroAllocation(C, CE, 0, State);
State = ProcessZeroAllocation(C, CE, 1, State);
- } else if (FunI == II_free) {
+ } else if ((FunI == II_free) || (FunI == II_free_dbg)) {
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
} else if (FunI == II_strdup || FunI == II_win_strdup ||
- FunI == II_wcsdup || FunI == II_win_wcsdup) {
+ FunI == II_wcsdup || FunI == II_win_wcsdup ||
+ FunI == II_wcsdup_dbg || FunI == II_strdup_dbg ||
+ FunI == II_mbsdup || FunI == II_mbsdup_dbg ||
+ FunI == II_tempnam || FunI == II_win_tempnam ||
+ FunI == II_win_tempnam_dbg || FunI == II_wtempnam ||
+ FunI == II_wtempnam_dbg) {
State = MallocUpdateRefState(C, CE, State);
} else if (FunI == II_strndup) {
State = MallocUpdateRefState(C, CE, State);
@@ -1054,7 +1090,7 @@
if (!State)
return nullptr;
- if (Att->getModule() != II_malloc)
+ if ((Att->getModule() != II_malloc) && (Att->getModule() != II_malloc_dbg))
return nullptr;
OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
@@ -1148,7 +1184,7 @@
if (!State)
return nullptr;
- if (Att->getModule() != II_malloc)
+ if ((Att->getModule() != II_malloc) && (Att->getModule() != II_malloc_dbg))
return nullptr;
bool ReleasedAllocated = false;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits