Bug Summary

File:projects/compiler-rt/lib/profile/InstrProfilingFile.c
Location:line 181, column 3
Description:Potential leak of memory pointed to by 'Allocated'

Annotated Source Code

1/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
2|*
3|* The LLVM Compiler Infrastructure
4|*
5|* This file is distributed under the University of Illinois Open Source
6|* License. See LICENSE.TXT for details.
7|*
8\*===----------------------------------------------------------------------===*/
9
10#include "InstrProfiling.h"
11#include "InstrProfilingInternal.h"
12#include "InstrProfilingUtil.h"
13#include <errno(*__errno_location ()).h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#ifdef _MSC_VER
18/* For _alloca */
19#include <malloc.h>
20#endif
21
22
23#define UNCONST(ptr)((void *)(uintptr_t)(ptr)) ((void *)(uintptr_t)(ptr))
24
25/* Return 1 if there is an error, otherwise return 0. */
26static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
27 void **WriterCtx) {
28 uint32_t I;
29 FILE *File = (FILE *)*WriterCtx;
30 for (I = 0; I < NumIOVecs; I++) {
31 if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
32 IOVecs[I].NumElm)
33 return 1;
34 }
35 return 0;
36}
37
38COMPILER_RT_VISIBILITY__attribute__((visibility("hidden"))) ProfBufferIO *
39lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {
40 FreeHook = &free;
41 DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1);
42 VPBufferSize = BufferSz;
43 return lprofCreateBufferIO(fileWriter, File);
44}
45
46static void setupIOBuffer() {
47 const char *BufferSzStr = 0;
48 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
49 if (BufferSzStr && BufferSzStr[0]) {
50 VPBufferSize = atoi(BufferSzStr);
51 DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1);
52 }
53}
54
55static int writeFile(FILE *File) {
56 FreeHook = &free;
57 setupIOBuffer();
58 return lprofWriteData(fileWriter, File, lprofGetVPDataReader());
59}
60
61static int writeFileWithName(const char *OutputName) {
62 int RetVal;
63 FILE *OutputFile;
64 if (!OutputName || !OutputName[0])
65 return -1;
66
67 /* Append to the file to support profiling multiple shared objects. */
68 OutputFile = fopen(OutputName, "ab");
69 if (!OutputFile)
70 return -1;
71
72 RetVal = writeFile(OutputFile);
73
74 fclose(OutputFile);
75 return RetVal;
76}
77
78COMPILER_RT_WEAK__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
79COMPILER_RT_WEAK__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL((void*)0);
80
81static void truncateCurrentFile(void) {
82 const char *Filename;
83 FILE *File;
84
85 Filename = __llvm_profile_CurrentFilename;
86 if (!Filename || !Filename[0])
87 return;
88
89 /* Create the directory holding the file, if needed. */
90 if (strchr(Filename, '/')(__extension__ (__builtin_constant_p ('/') && !__builtin_constant_p
(Filename) && ('/') == '\0' ? (char *) __rawmemchr (
Filename, '/') : __builtin_strchr (Filename, '/')))
|| strchr(Filename, '\\')(__extension__ (__builtin_constant_p ('\\') && !__builtin_constant_p
(Filename) && ('\\') == '\0' ? (char *) __rawmemchr (
Filename, '\\') : __builtin_strchr (Filename, '\\')))
) {
91 char *Copy = (char *)COMPILER_RT_ALLOCA__builtin_alloca(strlen(Filename) + 1);
92 strcpy(Copy, Filename);
93 __llvm_profile_recursive_mkdir(Copy);
94 }
95
96 /* Truncate the file. Later we'll reopen and append. */
97 File = fopen(Filename, "w");
98 if (!File)
99 return;
100 fclose(File);
101}
102
103static void setFilename(const char *Filename, int OwnsFilename) {
104 /* Check if this is a new filename and therefore needs truncation. */
105 int NewFile = !__llvm_profile_CurrentFilename ||
106 (Filename && strcmp(Filename, __llvm_profile_CurrentFilename)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(Filename) && __builtin_constant_p (__llvm_profile_CurrentFilename
) && (__s1_len = __builtin_strlen (Filename), __s2_len
= __builtin_strlen (__llvm_profile_CurrentFilename), (!((size_t
)(const void *)((Filename) + 1) - (size_t)(const void *)(Filename
) == 1) || __s1_len >= 4) && (!((size_t)(const void
*)((__llvm_profile_CurrentFilename) + 1) - (size_t)(const void
*)(__llvm_profile_CurrentFilename) == 1) || __s2_len >= 4
)) ? __builtin_strcmp (Filename, __llvm_profile_CurrentFilename
) : (__builtin_constant_p (Filename) && ((size_t)(const
void *)((Filename) + 1) - (size_t)(const void *)(Filename) ==
1) && (__s1_len = __builtin_strlen (Filename), __s1_len
< 4) ? (__builtin_constant_p (__llvm_profile_CurrentFilename
) && ((size_t)(const void *)((__llvm_profile_CurrentFilename
) + 1) - (size_t)(const void *)(__llvm_profile_CurrentFilename
) == 1) ? __builtin_strcmp (Filename, __llvm_profile_CurrentFilename
) : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (__llvm_profile_CurrentFilename); int
__result = (((const unsigned char *) (const char *) (Filename
))[0] - __s2[0]); if (__s1_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) (Filename
))[1] - __s2[1]); if (__s1_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) (Filename
))[2] - __s2[2]); if (__s1_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (Filename
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
__llvm_profile_CurrentFilename) && ((size_t)(const void
*)((__llvm_profile_CurrentFilename) + 1) - (size_t)(const void
*)(__llvm_profile_CurrentFilename) == 1) && (__s2_len
= __builtin_strlen (__llvm_profile_CurrentFilename), __s2_len
< 4) ? (__builtin_constant_p (Filename) && ((size_t
)(const void *)((Filename) + 1) - (size_t)(const void *)(Filename
) == 1) ? __builtin_strcmp (Filename, __llvm_profile_CurrentFilename
) : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (Filename); int __result = (((const unsigned
char *) (const char *) (__llvm_profile_CurrentFilename))[0] -
__s2[0]); if (__s2_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) (__llvm_profile_CurrentFilename
))[1] - __s2[1]); if (__s2_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) (__llvm_profile_CurrentFilename
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (__llvm_profile_CurrentFilename
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (Filename
, __llvm_profile_CurrentFilename)))); })
);
107 if (__llvm_profile_OwnsFilename)
108 free(UNCONST(__llvm_profile_CurrentFilename)((void *)(uintptr_t)(__llvm_profile_CurrentFilename)));
109
110 __llvm_profile_CurrentFilename = Filename;
111 __llvm_profile_OwnsFilename = OwnsFilename;
112
113 /* If not a new file, append to support profiling multiple shared objects. */
114 if (NewFile)
115 truncateCurrentFile();
116}
117
118static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
119
120int getpid(void);
121static int setFilenamePossiblyWithPid(const char *Filename) {
122#define MAX_PID_SIZE16 16
123 char PidChars[MAX_PID_SIZE16] = {0};
124 int NumPids = 0, PidLength = 0, NumHosts = 0, HostNameLength = 0;
125 char *Allocated;
126 int I, J;
127 char Hostname[COMPILER_RT_MAX_HOSTLEN128];
128
129 /* Reset filename on NULL, except with env var which is checked by caller. */
130 if (!Filename) {
4
Taking false branch
131 resetFilenameToDefault();
132 return 0;
133 }
134
135 /* Check the filename for "%p", which indicates a pid-substitution. */
136 for (I = 0; Filename[I]; ++I)
5
Loop condition is true. Entering loop body
11
Loop condition is false. Execution continues on line 152
137 if (Filename[I] == '%') {
6
Taking true branch
138 if (Filename[++I] == 'p') {
7
Taking true branch
139 if (!NumPids++) {
8
Taking true branch
140 PidLength = snprintf(PidChars, MAX_PID_SIZE16, "%d", getpid());
141 if (PidLength <= 0)
9
Assuming 'PidLength' is > 0
10
Taking false branch
142 return -1;
143 }
144 } else if (Filename[I] == 'h') {
145 if (!NumHosts++)
146 if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)lprofGetHostName(Hostname, 128))
147 return -1;
148 HostNameLength = strlen(Hostname);
149 }
150 }
151
152 if (!(NumPids || NumHosts)) {
12
Taking false branch
153 setFilename(Filename, 0);
154 return 0;
155 }
156
157 /* Allocate enough space for the substituted filename. */
158 Allocated = malloc(I + NumPids*(PidLength - 2) +
13
Memory is allocated
159 NumHosts*(HostNameLength - 2) + 1);
160 if (!Allocated)
14
Assuming 'Allocated' is non-null
15
Taking false branch
161 return -1;
162
163 /* Construct the new filename. */
164 for (I = 0, J = 0; Filename[I]; ++I)
16
Loop condition is true. Entering loop body
19
Loop condition is false. Execution continues on line 177
165 if (Filename[I] == '%') {
17
Taking true branch
166 if (Filename[++I] == 'p') {
18
Taking true branch
167 memcpy(Allocated + J, PidChars, PidLength);
168 J += PidLength;
169 }
170 else if (Filename[I] == 'h') {
171 memcpy(Allocated + J, Hostname, HostNameLength);
172 J += HostNameLength;
173 }
174 /* Drop any unknown substitutions. */
175 } else
176 Allocated[J++] = Filename[I];
177 Allocated[J] = 0;
178
179 /* Use the computed name. */
180 setFilename(Allocated, 1);
181 return 0;
20
Potential leak of memory pointed to by 'Allocated'
182}
183
184static const char *getFilenameFromEnv(void) {
185 const char *Filename = getenv("LLVM_PROFILE_FILE");
186 if (!Filename || !Filename[0])
187 return 0;
188 return Filename;
189}
190
191/* This method is invoked by the runtime initialization hook
192 * InstrProfilingRuntime.o if it is linked in. Both user specified
193 * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE
194 * environment variable can override this default value. */
195COMPILER_RT_VISIBILITY__attribute__((visibility("hidden")))
196void __llvm_profile_initialize_file(void) {
197 const char *Filename;
198 /* Check if the filename has been initialized. */
199 if (__llvm_profile_CurrentFilename)
1
Assuming '__llvm_profile_CurrentFilename' is null
2
Taking false branch
200 return;
201
202 /* Detect the filename and truncate. */
203 Filename = getFilenameFromEnv();
204 if (!Filename || setFilenamePossiblyWithPid(Filename))
3
Calling 'setFilenamePossiblyWithPid'
205 resetFilenameToDefault();
206}
207
208/* This API is directly called by the user application code. It has the
209 * highest precedence compared with LLVM_PROFILE_FILE environment variable
210 * and command line option -fprofile-instr-generate=<profile_name>.
211 */
212COMPILER_RT_VISIBILITY__attribute__((visibility("hidden")))
213void __llvm_profile_set_filename(const char *Filename) {
214 setFilenamePossiblyWithPid(Filename);
215}
216
217/*
218 * This API is invoked by the global initializers emitted by Clang/LLVM when
219 * -fprofile-instr-generate=<..> is specified (vs -fprofile-instr-generate
220 * without an argument). This option has lower precedence than the
221 * LLVM_PROFILE_FILE environment variable.
222 */
223COMPILER_RT_VISIBILITY__attribute__((visibility("hidden")))
224void __llvm_profile_override_default_filename(const char *Filename) {
225 /* If the env var is set, skip setting filename from argument. */
226 const char *Env_Filename = getFilenameFromEnv();
227 if (Env_Filename)
228 return;
229 setFilenamePossiblyWithPid(Filename);
230}
231
232COMPILER_RT_VISIBILITY__attribute__((visibility("hidden")))
233int __llvm_profile_write_file(void) {
234 int rc;
235
236 GetEnvHook = &getenv;
237 /* Check the filename. */
238 if (!__llvm_profile_CurrentFilename) {
239 PROF_ERR("Failed to write file : %s\n", "Filename not set")fprintf(stderr, "LLVM Profile Error: " "Failed to write file : %s\n"
, "Filename not set");
;
240 return -1;
241 }
242
243 /* Check if there is llvm/runtime version mismatch. */
244 if (GET_VERSION(__llvm_profile_get_version())((__llvm_profile_get_version()) & ~0xff00000000000000ULL) != INSTR_PROF_RAW_VERSION4) {
245 PROF_ERR("Runtime and instrumentation version mismatch : "fprintf(stderr, "LLVM Profile Error: " "Runtime and instrumentation version mismatch : "
"expected %d, but get %d\n", 4, (int)((__llvm_profile_get_version
()) & ~0xff00000000000000ULL));
246 "expected %d, but get %d\n",fprintf(stderr, "LLVM Profile Error: " "Runtime and instrumentation version mismatch : "
"expected %d, but get %d\n", 4, (int)((__llvm_profile_get_version
()) & ~0xff00000000000000ULL));
247 INSTR_PROF_RAW_VERSION,fprintf(stderr, "LLVM Profile Error: " "Runtime and instrumentation version mismatch : "
"expected %d, but get %d\n", 4, (int)((__llvm_profile_get_version
()) & ~0xff00000000000000ULL));
248 (int)GET_VERSION(__llvm_profile_get_version()))fprintf(stderr, "LLVM Profile Error: " "Runtime and instrumentation version mismatch : "
"expected %d, but get %d\n", 4, (int)((__llvm_profile_get_version
()) & ~0xff00000000000000ULL));
;
249 return -1;
250 }
251
252 /* Write the file. */
253 rc = writeFileWithName(__llvm_profile_CurrentFilename);
254 if (rc)
255 PROF_ERR("Failed to write file \"%s\": %s\n",fprintf(stderr, "LLVM Profile Error: " "Failed to write file \"%s\": %s\n"
, __llvm_profile_CurrentFilename, strerror((*__errno_location
())));
256 __llvm_profile_CurrentFilename, strerror(errno))fprintf(stderr, "LLVM Profile Error: " "Failed to write file \"%s\": %s\n"
, __llvm_profile_CurrentFilename, strerror((*__errno_location
())));
;
257 return rc;
258}
259
260static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
261
262COMPILER_RT_VISIBILITY__attribute__((visibility("hidden")))
263int __llvm_profile_register_write_file_atexit(void) {
264 static int HasBeenRegistered = 0;
265
266 if (HasBeenRegistered)
267 return 0;
268
269 lprofSetupValueProfiler();
270
271 HasBeenRegistered = 1;
272 return atexit(writeFileWithoutReturn);
273}