clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mimegen.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -fno-plt -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/buildbot/lwan-worker/clang-analyze/build/src/bin/tools -resource-dir /usr/lib/clang/14.0.6 -include /home/buildbot/lwan-worker/clang-analyze/build/lwan-build-config.h -D _FILE_OFFSET_BITS=64 -D _TIME_BITS=64 -I /home/buildbot/lwan-worker/clang-analyze/build/src/lib/missing -I /usr/include/python3.10 -I /usr/include/luajit-2.1 -I /usr/include/valgrind -I /home/buildbot/lwan-worker/clang-analyze/build/src/lib -internal-isystem /usr/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../x86_64-pc-linux-gnu/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -Wno-free-nonheap-object -std=gnu99 -fdebug-compilation-dir=/home/buildbot/lwan-worker/clang-analyze/build/src/bin/tools -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/buildbot/lwan-worker/clang-analyze/CLANG/2022-10-11-063648-3239739-1 -x c /home/buildbot/lwan-worker/clang-analyze/build/src/bin/tools/mimegen.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | #include <assert.h> |
21 | #include <ctype.h> |
22 | #include <errno.h> |
23 | #include <fcntl.h> |
24 | #include <stdint.h> |
25 | #include <stdio.h> |
26 | #include <stdlib.h> |
27 | #include <string.h> |
28 | |
29 | #if defined(LWAN_HAVE_BROTLI) |
30 | #include <brotli/encode.h> |
31 | #elif defined(LWAN_HAVE_ZSTD) |
32 | #include <zstd.h> |
33 | #elif defined(LWAN_HAVE_ZOPFLI) |
34 | #include <zopfli/zopfli.h> |
35 | #else |
36 | #include <zlib.h> |
37 | #endif |
38 | |
39 | #include "../../lib/hash.h" |
40 | |
41 | struct output { |
42 | char *ptr; |
43 | size_t used, capacity; |
44 | }; |
45 | |
46 | static int |
47 | output_append_full(struct output *output, const char *str, size_t str_len) |
48 | { |
49 | size_t total_size = output->used + str_len; |
50 | |
51 | if (total_size >= output->capacity) { |
52 | char *tmp; |
53 | |
54 | while (total_size >= output->capacity) |
55 | output->capacity *= 2; |
56 | |
57 | tmp = realloc(output->ptr, output->capacity); |
58 | if (!tmp) |
59 | return -errno; |
60 | |
61 | output->ptr = tmp; |
62 | } |
63 | |
64 | memcpy(output->ptr + output->used, str, str_len); |
65 | output->used = total_size; |
66 | |
67 | return 0; |
68 | } |
69 | |
70 | static int output_append_padded(struct output *output, const char *str) |
71 | { |
72 | size_t str_len = strlen(str); |
73 | |
74 | assert(str_len <= 8); |
75 | |
76 | int r = output_append_full(output, str, str_len); |
77 | if (r < 0) |
78 | return r; |
79 | |
80 | if (str_len != 8) |
81 | return output_append_full(output, "\0\0\0\0\0\0\0\0", 8 - str_len); |
82 | |
83 | return 0; |
84 | } |
85 | |
86 | static int output_append(struct output *output, const char *str) |
87 | { |
88 | return output_append_full(output, str, strlen(str) + 1); |
89 | } |
90 | |
91 | static int compare_ext(const void *a, const void *b) |
92 | { |
93 | const char **exta = (const char **)a; |
94 | const char **extb = (const char **)b; |
95 | |
96 | return strcasecmp(*exta, *extb); |
97 | } |
98 | |
99 | static char *strend(char *str, char ch) |
100 | { |
101 | str = strchr(str, ch); |
102 | if (str) { |
103 | *str = '\0'; |
104 | return str + 1; |
105 | } |
106 | return NULL; |
107 | } |
108 | |
109 | static char *compress_output(const struct output *output, size_t *outlen) |
110 | { |
111 | char *compressed; |
112 | |
113 | #if defined(LWAN_HAVE_BROTLI) |
114 | *outlen = BrotliEncoderMaxCompressedSize(output->used); |
115 | |
116 | compressed = malloc(*outlen); |
117 | if (!compressed) { |
118 | fprintf(stderr, "Could not allocate memory for compressed data\n"); |
119 | exit(1); |
120 | } |
121 | |
122 | if (BrotliEncoderCompress(BROTLI_MAX_QUALITY, BROTLI_MAX_WINDOW_BITS, |
123 | BROTLI_MODE_TEXT, output->used, |
124 | (const unsigned char *)output->ptr, outlen, |
125 | (unsigned char *)compressed) != BROTLI_TRUE) { |
126 | fprintf(stderr, "Could not compress mime type table with Brotli\n"); |
127 | exit(1); |
128 | } |
129 | #elif defined(LWAN_HAVE_ZSTD) |
130 | *outlen = ZSTD_compressBound(output->used); |
131 | |
132 | compressed = malloc(*outlen); |
133 | if (!compressed) { |
134 | fprintf(stderr, "Could not allocate memory for compressed data\n"); |
135 | exit(1); |
136 | } |
137 | |
138 | *outlen = ZSTD_compress(compressed, *outlen, output->ptr, output->used, |
139 | ZSTD_maxCLevel()); |
140 | if (ZSTD_isError(*outlen)) { |
141 | fprintf(stderr, "Could not compress mime type table with ZSTD\n"); |
142 | exit(1); |
143 | } |
144 | #elif defined(LWAN_HAVE_ZOPFLI) |
145 | ZopfliOptions opts; |
146 | |
147 | *outlen = 0; |
148 | |
149 | ZopfliInitOptions(&opts); |
150 | ZopfliCompress(&opts, ZOPFLI_FORMAT_ZLIB, |
151 | (const unsigned char *)output->ptr, output->used, |
152 | (unsigned char **)&compressed, outlen); |
153 | #else |
154 | *outlen = compressBound((uLong)output->used); |
155 | compressed = malloc(*outlen); |
156 | if (!compressed) { |
157 | fprintf(stderr, "Could not allocate memory for compressed data\n"); |
158 | exit(1); |
159 | } |
160 | if (compress2((Bytef *)compressed, outlen, (const Bytef *)output->ptr, |
161 | output->used, 9) != Z_OK) { |
162 | fprintf(stderr, "Could not compress data with zlib\n"); |
163 | exit(1); |
164 | } |
165 | #endif |
166 | if (!*outlen) { |
167 | free(compressed); |
168 | return NULL; |
169 | } |
170 | |
171 | return compressed; |
172 | } |
173 | |
174 | static bool is_builtin_mime_type(const char *mime) |
175 | { |
176 | |
177 | |
178 | if (streq(mime, "application/octet-stream")) |
179 | return true; |
180 | if (streq(mime, "text/javascript")) |
181 | return true; |
182 | if (streq(mime, "image/jpeg")) |
183 | return true; |
184 | if (streq(mime, "image/gif")) |
185 | return true; |
186 | if (streq(mime, "image/png")) |
187 | return true; |
188 | if (streq(mime, "text/html")) |
189 | return true; |
190 | if (streq(mime, "text/css")) |
191 | return true; |
192 | if (streq(mime, "text/plain")) |
193 | return true; |
194 | return false; |
195 | } |
196 | |
197 | int main(int argc, char *argv[]) |
198 | { |
199 | FILE *fp; |
200 | char buffer[256]; |
201 | struct output output = { .capacity = 1024 }; |
202 | size_t compressed_size; |
203 | char *compressed, *ext; |
204 | struct hash *ext_mime; |
205 | struct hash_iter iter; |
206 | const char **exts, *key; |
207 | size_t i; |
208 | |
209 | if (argc < 2) { |
| |
| |
210 | fprintf(stderr, "Usage: %s /path/to/mime.types\n", argv[0]); |
211 | return 1; |
212 | } |
213 | |
214 | fp = fopen(argv[1], "re"); |
215 | if (!fp) { |
| 3 | | Assuming 'fp' is non-null | |
|
| |
216 | fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno)); |
217 | return 1; |
218 | } |
219 | |
220 | ext_mime = hash_str_new(free, free); |
221 | if (!ext_mime) { |
| 5 | | Assuming 'ext_mime' is non-null | |
|
| |
222 | fprintf(stderr, "Could not allocate hash table\n"); |
223 | fclose(fp); |
224 | return 1; |
225 | } |
226 | |
227 | while (fgets(buffer, sizeof(buffer), fp)) { |
| 7 | | Loop condition is true. Entering loop body | |
|
228 | char *start = buffer, *end, *tab, *mime_type; |
229 | |
230 | while (*start && isspace(*start)) |
| 8 | | Assuming the condition is false | |
|
231 | start++; |
232 | if (*start == '#') |
| |
233 | continue; |
234 | |
235 | strend(start, '\n'); |
236 | strend(start, '#'); |
237 | tab = strend(start, '\t'); |
238 | if (!tab) |
| |
239 | continue; |
240 | |
241 | mime_type = start; |
242 | if (is_builtin_mime_type(mime_type)) |
243 | continue; |
244 | |
245 | while (*tab && *tab == '\t') |
| 11 | | Assuming the condition is true | |
|
| 12 | | Assuming the condition is false | |
|
| 13 | | Loop condition is false. Execution continues on line 248 | |
|
246 | tab++; |
247 | |
248 | for (ext = tab; *ext; ext += end - ext + 1) { |
| 14 | | Loop condition is true. Entering loop body | |
|
249 | char *k, *v; |
250 | int r; |
251 | |
252 | end = strchr(ext, ' '); |
253 | if (!end) |
| 15 | | Assuming 'end' is non-null | |
|
| |
254 | end = strchr(ext, '\0'); |
255 | *end = '\0'; |
256 | |
257 | if (end - ext > 8) { |
| 17 | | Assuming the condition is false | |
|
| |
258 | |
259 | ext[8] = '\0'; |
260 | } |
261 | |
262 | k = strdup(ext); |
263 | v = strdup(mime_type); |
| |
264 | |
265 | if (!k || !v) { |
| |
266 | fprintf(stderr, "Could not allocate memory\n"); |
| 21 | | Potential leak of memory pointed to by 'v' |
|
267 | fclose(fp); |
268 | return 1; |
269 | } |
270 | |
271 | r = hash_add_unique(ext_mime, k, v); |
272 | if (r < 0) { |
273 | free(k); |
274 | free(v); |
275 | |
276 | if (r != -EEXIST) { |
277 | fprintf(stderr, "Could not add extension to hash table\n"); |
278 | fclose(fp); |
279 | return 1; |
280 | } |
281 | } |
282 | } |
283 | } |
284 | |
285 | |
286 | exts = calloc(hash_get_count(ext_mime), sizeof(char *)); |
287 | if (!exts) { |
288 | fprintf(stderr, "Could not allocate extension array\n"); |
289 | fclose(fp); |
290 | return 1; |
291 | } |
292 | hash_iter_init(ext_mime, &iter); |
293 | for (i = 0; hash_iter_next(&iter, (const void **)&key, NULL); i++) |
294 | exts[i] = key; |
295 | qsort(exts, hash_get_count(ext_mime), sizeof(char *), compare_ext); |
296 | |
297 | |
298 | output.ptr = malloc(output.capacity); |
299 | if (!output.ptr) { |
300 | fprintf(stderr, "Could not allocate temporary memory\n"); |
301 | fclose(fp); |
302 | return 1; |
303 | } |
304 | for (i = 0; i < hash_get_count(ext_mime); i++) { |
305 | char ext_lower[9] = {0}; |
306 | |
307 | strncpy(ext_lower, exts[i], 8); |
308 | |
309 | for (char *p = ext_lower; *p; p++) |
310 | *p &= ~0x20; |
311 | |
312 | if (output_append_padded(&output, ext_lower) < 0) { |
313 | fprintf(stderr, "Could not append to output\n"); |
314 | fclose(fp); |
315 | return 1; |
316 | } |
317 | } |
318 | for (i = 0; i < hash_get_count(ext_mime); i++) { |
319 | if (output_append(&output, hash_find(ext_mime, exts[i])) < 0) { |
320 | fprintf(stderr, "Could not append to output\n"); |
321 | fclose(fp); |
322 | return 1; |
323 | } |
324 | } |
325 | |
326 | |
327 | compressed = compress_output(&output, &compressed_size); |
328 | if (!compressed) { |
329 | fprintf(stderr, "Could not compress data\n"); |
330 | fclose(fp); |
331 | return 1; |
332 | } |
333 | |
334 | |
335 | #if defined(LWAN_HAVE_BROTLI) |
336 | printf("/* Compressed with brotli */\n"); |
337 | #elif defined(LWAN_HAVE_ZSTD) |
338 | printf("/* Compressed with zstd */\n"); |
339 | #elif defined(LWAN_HAVE_ZOPFLI) |
340 | printf("/* Compressed with zopfli (deflate) */\n"); |
341 | #else |
342 | printf("/* Compressed with zlib (deflate) */\n"); |
343 | #endif |
344 | printf("#pragma once\n"); |
345 | printf("#define MIME_UNCOMPRESSED_LEN %zu\n", output.used); |
346 | printf("#define MIME_COMPRESSED_LEN %lu\n", compressed_size); |
347 | printf("#define MIME_ENTRIES %d\n", hash_get_count(ext_mime)); |
348 | printf("static const unsigned char mime_entries_compressed[] = {\n"); |
349 | for (i = 1; compressed_size; compressed_size--, i++) |
350 | printf("0x%02x,%c", compressed[i - 1] & 0xff, " \n"[i % 13 == 0]); |
351 | printf("};\n"); |
352 | |
353 | free(compressed); |
354 | free(output.ptr); |
355 | free(exts); |
356 | hash_free(ext_mime); |
357 | fclose(fp); |
358 | |
359 | return 0; |
360 | } |