1 | // RUN: %clang_analyze_cc1 -analyzer-checker=unix.Malloc -analyzer-inline-max-stack-depth=5 -verify %s |
2 | |
3 | #include "Inputs/system-header-simulator.h" |
4 | |
5 | void *malloc(size_t); |
6 | void *valloc(size_t); |
7 | void free(void *); |
8 | void *realloc(void *ptr, size_t size); |
9 | void *reallocf(void *ptr, size_t size); |
10 | void *calloc(size_t nmemb, size_t size); |
11 | |
12 | void exit(int) __attribute__ ((__noreturn__)); |
13 | void *memcpy(void * restrict s1, const void * restrict s2, size_t n); |
14 | size_t strlen(const char *); |
15 | |
16 | static void my_malloc1(void **d, size_t size) { |
17 | *d = malloc(size); |
18 | } |
19 | |
20 | static void *my_malloc2(int elevel, size_t size) { |
21 | void *data; |
22 | data = malloc(size); |
23 | if (data == 0) |
24 | exit(0); |
25 | return data; |
26 | } |
27 | |
28 | static void my_free1(void *p) { |
29 | free(p); |
30 | } |
31 | |
32 | static void test1() { |
33 | void *data = 0; |
34 | my_malloc1(&data, 4); |
35 | } // expected-warning {{Potential leak of memory pointed to by 'data'}} |
36 | |
37 | static void test11() { |
38 | void *data = 0; |
39 | my_malloc1(&data, 4); |
40 | my_free1(data); |
41 | } |
42 | |
43 | static void testUniqueingByallocationSiteInTopLevelFunction() { |
44 | void *data = my_malloc2(1, 4); |
45 | data = 0; |
46 | int x = 5;// expected-warning {{Potential leak of memory pointed to by 'data'}} |
47 | data = my_malloc2(1, 4); |
48 | } // expected-warning {{Potential leak of memory pointed to by 'data'}} |
49 | |
50 | static void test3() { |
51 | void *data = my_malloc2(1, 4); |
52 | free(data); |
53 | data = my_malloc2(1, 4); |
54 | free(data); |
55 | } |
56 | |
57 | int test4() { |
58 | int *data = (int*)my_malloc2(1, 4); |
59 | my_free1(data); |
60 | data = (int *)my_malloc2(1, 4); |
61 | my_free1(data); |
62 | return *data; // expected-warning {{Use of memory after it is freed}} |
63 | } |
64 | |
65 | void test6() { |
66 | int *data = (int *)my_malloc2(1, 4); |
67 | my_free1((int*)data); |
68 | my_free1((int*)data); // expected-warning{{Use of memory after it is freed}} |
69 | } |
70 | |
71 | // TODO: We should warn here. |
72 | void test5() { |
73 | int *data; |
74 | my_free1((int*)data); |
75 | } |
76 | |
77 | static char *reshape(char *in) { |
78 | return 0; |
79 | } |
80 | |
81 | void testThatRemoveDeadBindingsRunBeforeEachCall() { |
82 | char *v = malloc(12); |
83 | v = reshape(v); |
84 | v = reshape(v);// expected-warning {{Potential leak of memory pointed to by 'v'}} |
85 | } |
86 | |
87 | // Test that we keep processing after 'return;' |
88 | void fooWithEmptyReturn(int x) { |
89 | if (x) |
90 | return; |
91 | x++; |
92 | return; |
93 | } |
94 | |
95 | int uafAndCallsFooWithEmptyReturn() { |
96 | int *x = (int*)malloc(12); |
97 | free(x); |
98 | fooWithEmptyReturn(12); |
99 | return *x; // expected-warning {{Use of memory after it is freed}} |
100 | } |
101 | |
102 | |
103 | // If we inline any of the malloc-family functions, the checker shouldn't also |
104 | // try to do additional modeling. <rdar://problem/12317671> |
105 | char *strndup(const char *str, size_t n) { |
106 | if (!str) |
107 | return 0; |
108 | |
109 | // DO NOT FIX. This is to test that we are actually using the inlined |
110 | // behavior! |
111 | if (n < 5) |
112 | return 0; |
113 | |
114 | size_t length = strlen(str); |
115 | if (length < n) |
116 | n = length; |
117 | |
118 | char *result = malloc(n + 1); |
119 | memcpy(result, str, n); |
120 | result[n] = '\0'; |
121 | return result; |
122 | } |
123 | |
124 | void useStrndup(size_t n) { |
125 | if (n == 0) { |
126 | (void)strndup(0, 20); // no-warning |
127 | return; |
128 | } else if (n < 5) { |
129 | (void)strndup("hi there", n); // no-warning |
130 | return; |
131 | } else { |
132 | (void)strndup("hi there", n); |
133 | return; // expected-warning{{leak}} |
134 | } |
135 | } |
136 | |