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 KernelZeroFlagVal; void initIdentifierInfo(ASTContext &C) const; @@ -543,6 +552,7 @@ 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"); @@ -551,6 +561,20 @@ 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,7 +610,8 @@ 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; } @@ -594,7 +619,13 @@ 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; 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}} @@ -1126,6 +1176,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'; @@ -1159,6 +1229,79 @@ 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 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 testWinWideTempnamNoLeakContentIsDefined(const wchar_t* dir, const wchar_t* prefix) { + wchar_t* fileName = _wtempnam(dir, prefix); + 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. @@ -1516,10 +1659,18 @@ 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}} +} + void passConstPtr(const char * ptr); void testPassConstPointer() {