99 lines · cpp
1// RUN: %clang_analyze_cc1 -verify \2// RUN: -analyzer-checker=core \3// RUN: -analyzer-checker=alpha.deadcode.UnreachableCode \4// RUN: -analyzer-checker=unix.Malloc \5// RUN: -analyzer-config unix.DynamicMemoryModeling:Optimistic=true %s6 7typedef __typeof(sizeof(int)) size_t;8void *malloc(size_t);9void free(void *);10 11struct MemoryAllocator {12 void __attribute((ownership_returns(malloc))) * my_malloc(size_t);13 void __attribute((ownership_takes(malloc, 2))) my_free(void *);14 void __attribute((ownership_holds(malloc, 2))) my_hold(void *);15};16 17void *myglobalpointer;18 19struct stuff {20 void *somefield;21};22 23struct stuff myglobalstuff;24 25void af1(MemoryAllocator &Alloc) {26 void *p = Alloc.my_malloc(12);27 return; // expected-warning{{Potential leak of memory pointed to by}}28}29 30void af1_b(MemoryAllocator &Alloc) {31 void *p = Alloc.my_malloc(12);32} // expected-warning{{Potential leak of memory pointed to by}}33 34void af1_c(MemoryAllocator &Alloc) {35 myglobalpointer = Alloc.my_malloc(12); // no-warning36}37 38// Test that we can pass out allocated memory via pointer-to-pointer.39void af1_e(MemoryAllocator &Alloc, void **pp) {40 *pp = Alloc.my_malloc(42); // no-warning41}42 43void af1_f(MemoryAllocator &Alloc, struct stuff *somestuff) {44 somestuff->somefield = Alloc.my_malloc(12); // no-warning45}46 47// Allocating memory for a field via multiple indirections to our arguments is OK.48void af1_g(MemoryAllocator &Alloc, struct stuff **pps) {49 *pps = (struct stuff *)Alloc.my_malloc(sizeof(struct stuff)); // no-warning50 (*pps)->somefield = Alloc.my_malloc(42); // no-warning51}52 53void af2(MemoryAllocator &Alloc) {54 void *p = Alloc.my_malloc(12);55 Alloc.my_free(p);56 free(p); // expected-warning{{Attempt to release already released memory}}57}58 59void af2b(MemoryAllocator &Alloc) {60 void *p = Alloc.my_malloc(12);61 free(p);62 Alloc.my_free(p); // expected-warning{{Attempt to release already released memory}}63}64 65void af2c(MemoryAllocator &Alloc) {66 void *p = Alloc.my_malloc(12);67 free(p);68 Alloc.my_hold(p); // expected-warning{{Attempt to release already released memory}}69}70 71// No leak if malloc returns null.72void af2e(MemoryAllocator &Alloc) {73 void *p = Alloc.my_malloc(12);74 if (!p)75 return; // no-warning76 free(p); // no-warning77}78 79// This case inflicts a possible double-free.80void af3(MemoryAllocator &Alloc) {81 void *p = Alloc.my_malloc(12);82 Alloc.my_hold(p);83 free(p); // expected-warning{{Attempt to release non-owned memory}}84}85 86void * af4(MemoryAllocator &Alloc) {87 void *p = Alloc.my_malloc(12);88 Alloc.my_free(p);89 return p; // expected-warning{{Use of memory after it is released}}90}91 92// This case is (possibly) ok, be conservative93void * af5(MemoryAllocator &Alloc) {94 void *p = Alloc.my_malloc(12);95 Alloc.my_hold(p);96 return p; // no-warning97}98 99