File: | projects/compiler-rt/lib/profile/InstrProfilingFile.c |
Location: | line 181, column 3 |
Description: | Potential leak of memory pointed to by 'Allocated' |
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. */ | |||
26 | static 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 | ||||
38 | COMPILER_RT_VISIBILITY__attribute__((visibility("hidden"))) ProfBufferIO * | |||
39 | lprofCreateBufferIOInternal(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 | ||||
46 | static 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 | ||||
55 | static int writeFile(FILE *File) { | |||
56 | FreeHook = &free; | |||
57 | setupIOBuffer(); | |||
58 | return lprofWriteData(fileWriter, File, lprofGetVPDataReader()); | |||
59 | } | |||
60 | ||||
61 | static 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 | ||||
78 | COMPILER_RT_WEAK__attribute__((weak)) int __llvm_profile_OwnsFilename = 0; | |||
79 | COMPILER_RT_WEAK__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL((void*)0); | |||
80 | ||||
81 | static 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 | ||||
103 | static 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 | ||||
118 | static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); } | |||
119 | ||||
120 | int getpid(void); | |||
121 | static 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) { | |||
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) | |||
137 | if (Filename[I] == '%') { | |||
138 | if (Filename[++I] == 'p') { | |||
139 | if (!NumPids++) { | |||
140 | PidLength = snprintf(PidChars, MAX_PID_SIZE16, "%d", getpid()); | |||
141 | if (PidLength <= 0) | |||
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)) { | |||
153 | setFilename(Filename, 0); | |||
154 | return 0; | |||
155 | } | |||
156 | ||||
157 | /* Allocate enough space for the substituted filename. */ | |||
158 | Allocated = malloc(I + NumPids*(PidLength - 2) + | |||
159 | NumHosts*(HostNameLength - 2) + 1); | |||
160 | if (!Allocated) | |||
161 | return -1; | |||
162 | ||||
163 | /* Construct the new filename. */ | |||
164 | for (I = 0, J = 0; Filename[I]; ++I) | |||
165 | if (Filename[I] == '%') { | |||
166 | if (Filename[++I] == 'p') { | |||
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; | |||
| ||||
182 | } | |||
183 | ||||
184 | static 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. */ | |||
195 | COMPILER_RT_VISIBILITY__attribute__((visibility("hidden"))) | |||
196 | void __llvm_profile_initialize_file(void) { | |||
197 | const char *Filename; | |||
198 | /* Check if the filename has been initialized. */ | |||
199 | if (__llvm_profile_CurrentFilename) | |||
| ||||
200 | return; | |||
201 | ||||
202 | /* Detect the filename and truncate. */ | |||
203 | Filename = getFilenameFromEnv(); | |||
204 | if (!Filename || setFilenamePossiblyWithPid(Filename)) | |||
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 | */ | |||
212 | COMPILER_RT_VISIBILITY__attribute__((visibility("hidden"))) | |||
213 | void __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 | */ | |||
223 | COMPILER_RT_VISIBILITY__attribute__((visibility("hidden"))) | |||
224 | void __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 | ||||
232 | COMPILER_RT_VISIBILITY__attribute__((visibility("hidden"))) | |||
233 | int __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 | ||||
260 | static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } | |||
261 | ||||
262 | COMPILER_RT_VISIBILITY__attribute__((visibility("hidden"))) | |||
263 | int __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 | } |