Bug Summary

File:lwan.c
Warning:line 338, column 17
Potential memory leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name lwan.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 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -fno-plt -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/buildbot/lwan-worker/clang-analyze/build/src/lib -resource-dir /usr/lib/clang/13.0.1 -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/luajit-2.1 -I /usr/include/valgrind -I /home/buildbot/lwan-worker/clang-analyze/build/src/lib -I /home/buildbot/lwan-worker/clang-analyze/build -internal-isystem /usr/lib/clang/13.0.1/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.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/lib -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-02-19-073853-1494865-1 -x c /home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c
1/*
2 * lwan - simple web server
3 * Copyright (c) 2012, 2013 L. A. F. Pereira <l@tia.mat.br>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 * USA.
19 */
20
21#define _GNU_SOURCE
22#include <assert.h>
23#include <ctype.h>
24#include <dlfcn.h>
25#include <errno(*__errno_location ()).h>
26#include <fcntl.h>
27#include <libproc.h>
28#include <limits.h>
29#include <signal.h>
30#include <stdlib.h>
31#include <string.h>
32#include <sys/resource.h>
33#include <sys/socket.h>
34#include <sys/types.h>
35#include <unistd.h>
36
37#include "lwan-private.h"
38
39#include "lwan-config.h"
40#include "lwan-http-authorize.h"
41
42#if defined(HAVE_LUA)
43#include "lwan-lua.h"
44#endif
45
46/* Ideally, this would check if all items in enum lwan_request_flags,
47 * when bitwise-or'd together, would not have have any bit set that
48 * is also set in REQUEST_METHOD_MASK. */
49static_assert_Static_assert(REQUEST_ACCEPT_DEFLATE > REQUEST_METHOD_MASK,
50 "enough bits to store request methods");
51
52/* See detect_fastest_monotonic_clock() */
53clockid_t monotonic_clock_id = CLOCK_MONOTONIC1;
54
55static const struct lwan_config default_config = {
56 .listener = "localhost:8080",
57 .keep_alive_timeout = 15,
58 .quiet = false0,
59 .proxy_protocol = false0,
60 .allow_cors = false0,
61 .expires = 1 * ONE_WEEK(((60 * 60) * 24) * 7),
62 .n_threads = 0,
63 .max_post_data_size = 10 * DEFAULT_BUFFER_SIZE4096,
64 .allow_post_temp_file = false0,
65 .max_put_data_size = 10 * DEFAULT_BUFFER_SIZE4096,
66 .allow_put_temp_file = false0,
67};
68
69LWAN_HANDLER(brew_coffee)static enum lwan_http_status lwan_handler_brew_coffee( struct
lwan_request *, struct lwan_response *, void *); static const
struct lwan_handler_info __attribute__((used, section("lwan_handler"
))) lwan_handler_info_brew_coffee = {.name = "brew_coffee", .
handler = lwan_handler_brew_coffee}; static enum lwan_http_status
lwan_handler_brew_coffee( struct lwan_request *request __attribute__
((unused)), struct lwan_response *response __attribute__((unused
)), void *data __attribute__((unused)))
70{
71 /* Placeholder handler so that __start_lwan_handler and __stop_lwan_handler
72 * symbols will get defined.
73 */
74 return HTTP_I_AM_A_TEAPOT;
75}
76
77__attribute__((no_sanitize_address))
78static void *find_handler(const char *name)
79{
80 const struct lwan_handler_info *handler;
81
82 LWAN_SECTION_FOREACH(lwan_handler, handler)for (handler = ({ extern const typeof(*handler) __start_lwan_handler
[]; __start_lwan_handler; }); handler < ({ extern const typeof
(*handler) __stop_lwan_handler[]; __stop_lwan_handler; }); (handler
)++)
{
83 if (streq(handler->name, name))
84 return handler->handler;
85 }
86
87 return NULL((void*)0);
88}
89
90__attribute__((no_sanitize_address))
91static const struct lwan_module *find_module(const char *name)
92{
93 const struct lwan_module_info *module;
94
95 LWAN_SECTION_FOREACH(lwan_module, module)for (module = ({ extern const typeof(*module) __start_lwan_module
[]; __start_lwan_module; }); module < ({ extern const typeof
(*module) __stop_lwan_module[]; __stop_lwan_module; }); (module
)++)
{
96 if (streq(module->name, name))
97 return module->module;
98 }
99
100 return NULL((void*)0);
101}
102
103static void destroy_urlmap(void *data)
104{
105 struct lwan_url_map *url_map = data;
106
107 if (url_map->module) {
108 const struct lwan_module *module = url_map->module;
109
110 if (module->destroy)
111 module->destroy(url_map->data);
112 } else if (url_map->data && url_map->flags & HANDLER_DATA_IS_HASH_TABLE) {
113 hash_free(url_map->data);
114 }
115
116 free(url_map->authorization.realm);
117 free(url_map->authorization.password_file);
118 free((char *)url_map->prefix);
119 free(url_map);
120}
121
122static struct lwan_url_map *add_url_map(struct lwan_trie *t, const char *prefix,
123 const struct lwan_url_map *map)
124{
125 struct lwan_url_map *copy = malloc(sizeof(*copy));
126
127 if (!copy)
128 lwan_status_critical_perror("Could not copy URL map")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 128, __FUNCTION__, "Could not copy URL map")
;
129
130 memcpy(copy, map, sizeof(*copy));
131
132 copy->prefix = strdup(prefix ? prefix : copy->prefix);
133 if (!copy->prefix)
134 lwan_status_critical_perror("Could not copy URL prefix")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 134, __FUNCTION__, "Could not copy URL prefix")
;
135
136 copy->prefix_len = strlen(copy->prefix);
137 lwan_trie_add(t, copy->prefix, copy);
138
139 return copy;
140}
141
142static bool_Bool can_override_header(const char *name)
143{
144 /* NOTE: Update lwan_prepare_response_header_full() in lwan-response.c
145 * if new headers are added here. */
146
147 if (!strcasecmp(name, "Date"))
148 return false0;
149 if (!strcasecmp(name, "Expires"))
150 return false0;
151 if (!strcasecmp(name, "WWW-Authenticate"))
152 return false0;
153 if (!strcasecmp(name, "Connection"))
154 return false0;
155 if (!strcasecmp(name, "Content-Type"))
156 return false0;
157 if (!strcasecmp(name, "Transfer-Encoding"))
158 return false0;
159 if (!strncasecmp(name, "Access-Control-Allow-",
160 sizeof("Access-Control-Allow-") - 1))
161 return false0;
162
163 return true1;
164}
165
166static void build_response_headers(struct lwan *l,
167 const struct lwan_key_value *kv)
168{
169 struct lwan_strbuf strbuf;
170 bool_Bool set_server = false0;
171
172 assert(l)((void) sizeof ((l) ? 1 : 0), __extension__ ({ if (l) ; else __assert_fail
("l", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 172, __extension__ __PRETTY_FUNCTION__); }))
;
173
174 lwan_strbuf_init(&strbuf);
175
176 for (; kv && kv->key; kv++) {
177 if (!can_override_header(kv->key)) {
178 lwan_status_warning("Cannot override header '%s'", kv->key)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 178, __FUNCTION__, "Cannot override header '%s'", kv->key
)
;
179 } else {
180 if (!strcasecmp(kv->key, "Server"))
181 set_server = true1;
182
183 lwan_strbuf_append_printf(&strbuf, "\r\n%s: %s", kv->key,
184 kv->value);
185 }
186 }
187
188 if (!set_server)
189 lwan_strbuf_append_strz(&strbuf, "\r\nServer: lwan");
190
191 lwan_strbuf_append_strz(&strbuf, "\r\n\r\n");
192
193 l->headers = (struct lwan_value){.value = lwan_strbuf_get_buffer(&strbuf),
194 .len = lwan_strbuf_get_length(&strbuf)};
195}
196
197static void parse_global_headers(struct config *c,
198 struct lwan *lwan)
199{
200 struct lwan_key_value_array hdrs;
201 const struct config_line *l;
202 struct lwan_key_value *kv;
203
204 lwan_key_value_array_init(&hdrs);
205
206 while ((l = config_read_line(c))) {
207 switch (l->type) {
208 case CONFIG_LINE_TYPE_SECTION:
209 config_error(
210 c, "No sections are supported under the 'headers' section");
211 goto cleanup;
212
213 case CONFIG_LINE_TYPE_LINE:
214 kv = lwan_key_value_array_append(&hdrs);
215 if (!kv) {
216 lwan_status_critical_perror(lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 217, __FUNCTION__, "Could not allocate memory for custom response header"
)
217 "Could not allocate memory for custom response header")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 217, __FUNCTION__, "Could not allocate memory for custom response header"
)
;
218 }
219
220 kv->key = strdup(l->key);
221 if (!kv->key) {
222 lwan_status_critical_perror(lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 223, __FUNCTION__, "Could not allocate memory for custom response header"
)
223 "Could not allocate memory for custom response header")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 223, __FUNCTION__, "Could not allocate memory for custom response header"
)
;
224 }
225
226 kv->value = strdup(l->value);
227 if (!kv->value) {
228 lwan_status_critical_perror(lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 229, __FUNCTION__, "Could not allocate memory for custom response header"
)
229 "Could not allocate memory for custom response header")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 229, __FUNCTION__, "Could not allocate memory for custom response header"
)
;
230 }
231 break;
232
233 case CONFIG_LINE_TYPE_SECTION_END:
234 kv = lwan_key_value_array_append(&hdrs);
235 if (!kv) {
236 lwan_status_critical_perror(lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 237, __FUNCTION__, "Could not allocate memory for custom response header"
)
237 "Could not allocate memory for custom response header")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 237, __FUNCTION__, "Could not allocate memory for custom response header"
)
;
238 }
239
240 kv->key = NULL((void*)0);
241 kv->value = NULL((void*)0);
242
243 build_response_headers(lwan, lwan_key_value_array_get_array(&hdrs));
244 goto cleanup;
245 }
246 }
247
248 config_error(c, "EOF while looking for end of 'headers' section");
249
250cleanup:
251 LWAN_ARRAY_FOREACH (&hdrs, kv)for (kv = (&hdrs)->base.base; kv < ((typeof(kv))(&
hdrs)->base.base + (&hdrs)->base.elements); kv++)
{
252 free(kv->key);
253 free(kv->value);
254 }
255 lwan_key_value_array_reset(&hdrs);
256}
257
258static void parse_listener_prefix_authorization(struct config *c,
259 const struct config_line *l,
260 struct lwan_url_map *url_map)
261{
262 if (!streq(l->value, "basic")) {
263 config_error(c, "Only basic authorization supported");
264 return;
265 }
266
267 memset(&url_map->authorization, 0, sizeof(url_map->authorization));
268
269 while ((l = config_read_line(c))) {
270 switch (l->type) {
271 case CONFIG_LINE_TYPE_LINE:
272 if (streq(l->key, "realm")) {
273 free(url_map->authorization.realm);
274 url_map->authorization.realm = strdup(l->value);
275 } else if (streq(l->key, "password_file")) {
276 free(url_map->authorization.password_file);
277 url_map->authorization.password_file = realpath(l->value, NULL((void*)0));
278 if (!url_map->authorization.password_file)
279 config_error(c, "Could not determine full path for password file: %s", l->value);
280 }
281 break;
282
283 case CONFIG_LINE_TYPE_SECTION:
284 config_error(c, "Unexpected section: %s", l->key);
285 goto error;
286
287 case CONFIG_LINE_TYPE_SECTION_END:
288 if (!url_map->authorization.realm)
289 url_map->authorization.realm = strdup("Lwan");
290 if (!url_map->authorization.password_file)
291 url_map->authorization.password_file = strdup("htpasswd");
292
293 url_map->flags |= HANDLER_MUST_AUTHORIZE;
294 return;
295 }
296 }
297
298 config_error(c, "Could not find end of authorization section");
299
300error:
301 free(url_map->authorization.realm);
302 free(url_map->authorization.password_file);
303}
304
305__attribute__((no_sanitize_address))
306static const char *get_module_name(const struct lwan_module *module)
307{
308 const struct lwan_module_info *iter;
309
310 LWAN_SECTION_FOREACH(lwan_module, iter)for (iter = ({ extern const typeof(*iter) __start_lwan_module
[]; __start_lwan_module; }); iter < ({ extern const typeof
(*iter) __stop_lwan_module[]; __stop_lwan_module; }); (iter)++
)
{
311 if (iter->module == module)
312 return iter->name;
313 }
314
315 return "<unknown>";
316}
317
318static void parse_listener_prefix(struct config *c,
319 const struct config_line *l,
320 struct lwan *lwan,
321 const struct lwan_module *module,
322 void *handler)
323{
324 struct lwan_url_map url_map = {};
325 struct hash *hash = hash_str_new(free, free);
326 char *prefix = strdupa(l->value)(__extension__ ({ const char *__old = (l->value); size_t __len
= strlen (__old) + 1; char *__new = (char *) __builtin_alloca
(__len); (char *) memcpy (__new, __old, __len); }))
;
327 struct config *isolated;
328
329 if (!hash)
21
Assuming 'hash' is non-null
22
Taking false branch
330 lwan_status_critical("Could not allocate hash table")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 330, __FUNCTION__, "Could not allocate hash table")
;
331
332 isolated = config_isolate_section(c, l);
333 if (!isolated) {
23
Assuming 'isolated' is non-null
24
Taking false branch
334 config_error(c, "Could not isolate configuration file");
335 goto out;
336 }
337
338 while ((l = config_read_line(c))) {
25
Loop condition is true. Entering loop body
29
Potential memory leak
339 switch (l->type) {
26
Control jumps to 'case CONFIG_LINE_TYPE_LINE:' at line 340
340 case CONFIG_LINE_TYPE_LINE:
341 hash_add(hash, strdup(l->key), strdup(l->value));
27
Memory is allocated
342 break;
28
Execution continues on line 338
343
344 case CONFIG_LINE_TYPE_SECTION:
345 if (streq(l->key, "authorization")) {
346 parse_listener_prefix_authorization(c, l, &url_map);
347 } else if (!config_skip_section(c, l)) {
348 config_error(c, "Could not skip section");
349 goto out;
350 }
351 break;
352
353 case CONFIG_LINE_TYPE_SECTION_END:
354 goto add_map;
355 }
356 }
357
358 config_error(c, "Expecting section end while parsing prefix");
359 goto out;
360
361add_map:
362 assert((handler && !module) || (!handler && module))((void) sizeof (((handler && !module) || (!handler &&
module)) ? 1 : 0), __extension__ ({ if ((handler && !
module) || (!handler && module)) ; else __assert_fail
("(handler && !module) || (!handler && module)"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 362, __extension__ __PRETTY_FUNCTION__); }))
;
363
364 if (handler) {
365 url_map.handler = handler;
366 url_map.flags |= HANDLER_PARSE_MASK | HANDLER_DATA_IS_HASH_TABLE;
367 url_map.data = hash;
368 url_map.module = NULL((void*)0);
369
370 hash = NULL((void*)0);
371 } else if (module->create_from_hash && module->handle_request) {
372 lwan_status_debug("Initializing module %s from config",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 373, __FUNCTION__, "Initializing module %s from config", get_module_name
(module))
373 get_module_name(module))lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 373, __FUNCTION__, "Initializing module %s from config", get_module_name
(module))
;
374
375 url_map.data = module->create_from_hash(prefix, hash);
376 if (!url_map.data) {
377 config_error(c, "Could not create module instance");
378 goto out;
379 }
380
381 if (module->parse_conf && !module->parse_conf(url_map.data, isolated)) {
382 const char *msg = config_last_error(isolated);
383
384 config_error(c, "Error from module: %s", msg ? msg : "Unknown");
385 goto out;
386 }
387
388 url_map.handler = module->handle_request;
389 url_map.flags |= module->flags;
390 url_map.module = module;
391 } else if (UNLIKELY(!module->create_from_hash)__builtin_expect(((!module->create_from_hash)), (0))) {
392 config_error(c, "Module isn't prepared to load settings from a file; "
393 "create_from_hash() method isn't present");
394 goto out;
395 } else if (UNLIKELY(!module->handle_request)__builtin_expect(((!module->handle_request)), (0))) {
396 config_error(c, "Module does not have handle_request() method");
397 goto out;
398 }
399
400 add_url_map(&lwan->url_map_trie, prefix, &url_map);
401
402out:
403 hash_free(hash);
404 config_close(isolated);
405}
406
407void lwan_set_url_map(struct lwan *l, const struct lwan_url_map *map)
408{
409 lwan_trie_destroy(&l->url_map_trie);
410 if (UNLIKELY(!lwan_trie_init(&l->url_map_trie, destroy_urlmap))__builtin_expect(((!lwan_trie_init(&l->url_map_trie, destroy_urlmap
))), (0))
)
411 lwan_status_critical_perror("Could not initialize trie")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 411, __FUNCTION__, "Could not initialize trie")
;
412
413 for (; map->prefix; map++) {
414 struct lwan_url_map *copy = add_url_map(&l->url_map_trie, NULL((void*)0), map);
415
416 if (copy->module && copy->module->create) {
417 lwan_status_debug("Initializing module %s from struct",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 418, __FUNCTION__, "Initializing module %s from struct", get_module_name
(copy->module))
418 get_module_name(copy->module))lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 418, __FUNCTION__, "Initializing module %s from struct", get_module_name
(copy->module))
;
419
420 copy->data = copy->module->create(map->prefix, copy->args);
421 if (!copy->data) {
422 lwan_status_critical("Could not initialize module %s",lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 423, __FUNCTION__, "Could not initialize module %s", get_module_name
(copy->module))
423 get_module_name(copy->module))lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 423, __FUNCTION__, "Could not initialize module %s", get_module_name
(copy->module))
;
424 }
425
426 copy->flags = copy->module->flags;
427 copy->handler = copy->module->handle_request;
428 } else {
429 copy->flags = HANDLER_PARSE_MASK;
430 }
431 }
432}
433
434const char *lwan_get_config_path(char *path_buf, size_t path_buf_len)
435{
436 char buffer[PATH_MAX4096];
437
438 if (proc_pidpath(getpid(), buffer, sizeof(buffer)) < 0)
439 goto out;
440
441 char *path = strrchr(buffer, '/');
442 if (!path)
443 goto out;
444 int ret = snprintf(path_buf, path_buf_len, "%s.conf", path + 1);
445 if (ret < 0 || ret >= (int)path_buf_len)
446 goto out;
447
448 return path_buf;
449
450out:
451 return "lwan.conf";
452}
453
454static void parse_tls_listener(struct config *conf, const struct config_line *line, struct lwan *lwan)
455{
456#if !defined(HAVE_MBEDTLS)
457 config_error(conf, "Lwan has been built without mbedTLS support");
458 return;
459#endif
460
461 lwan->config.tls_listener = strdup(line->value);
462 if (!lwan->config.tls_listener) {
463 config_error(conf, "Could not allocate memory for tls_listener");
464 return;
465 }
466
467 lwan->config.ssl.cert = NULL((void*)0);
468 lwan->config.ssl.key = NULL((void*)0);
469
470 while ((line = config_read_line(conf))) {
471 switch (line->type) {
472 case CONFIG_LINE_TYPE_SECTION_END:
473 if (!lwan->config.ssl.cert)
474 config_error(conf, "Missing path to certificate");
475 if (!lwan->config.ssl.key)
476 config_error(conf, "Missing path to private key");
477 return;
478 case CONFIG_LINE_TYPE_SECTION:
479 config_error(conf, "Unexpected section: %s", line->key);
480 return;
481 case CONFIG_LINE_TYPE_LINE:
482 if (streq(line->key, "cert")) {
483 free(lwan->config.ssl.cert);
484 lwan->config.ssl.cert = strdup(line->value);
485 if (!lwan->config.ssl.cert)
486 return lwan_status_critical("Could not copy string")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 486, __FUNCTION__, "Could not copy string")
;
487 } else if (streq(line->key, "key")) {
488 free(lwan->config.ssl.key);
489 lwan->config.ssl.key = strdup(line->value);
490 if (!lwan->config.ssl.key)
491 return lwan_status_critical("Could not copy string")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 491, __FUNCTION__, "Could not copy string")
;
492 } else if (streq(line->key, "hsts")) {
493 lwan->config.ssl.send_hsts_header = parse_bool(line->value, false0);
494 } else {
495 config_error(conf, "Unexpected key: %s", line->key);
496 }
497 }
498 }
499
500 config_error(conf, "Expecting section end while parsing SSL configuration");
501}
502
503static void
504parse_listener(struct config *c, const struct config_line *l, struct lwan *lwan)
505{
506 lwan->config.listener = strdup(l->value);
507 if (!lwan->config.listener)
508 config_error(c, "Could not allocate memory for listener");
509
510 while ((l = config_read_line(c))) {
511 switch (l->type) {
512 case CONFIG_LINE_TYPE_LINE:
513 config_error(c, "Unexpected key %s", l->key);
514 return;
515 case CONFIG_LINE_TYPE_SECTION:
516 config_error(c, "Unexpected section %s", l->key);
517 return;
518 case CONFIG_LINE_TYPE_SECTION_END:
519 return;
520 }
521 }
522
523 config_error(c, "Unexpected EOF while parsing listener");
524}
525
526static void
527parse_site(struct config *c, const struct config_line *l, struct lwan *lwan)
528{
529 while ((l = config_read_line(c))) {
14
Loop condition is true. Entering loop body
530 switch (l->type) {
15
Control jumps to 'case CONFIG_LINE_TYPE_SECTION:' at line 534
531 case CONFIG_LINE_TYPE_LINE:
532 config_error(c, "Expecting prefix section");
533 return;
534 case CONFIG_LINE_TYPE_SECTION:
535 if (l->key[0] == '&') {
16
Assuming the condition is true
17
Taking true branch
536 void *handler = find_handler(l->key + 1);
537 if (handler) {
18
Assuming 'handler' is non-null
19
Taking true branch
538 parse_listener_prefix(c, l, lwan, NULL((void*)0), handler);
20
Calling 'parse_listener_prefix'
539 continue;
540 }
541
542 config_error(c, "Could not find handler name: %s", l->key + 1);
543 return;
544 }
545
546 const struct lwan_module *module = find_module(l->key);
547 if (module) {
548 parse_listener_prefix(c, l, lwan, module, NULL((void*)0));
549 continue;
550 }
551
552 config_error(c, "Invalid section or module not found: %s", l->key);
553 return;
554 case CONFIG_LINE_TYPE_SECTION_END:
555 return;
556 }
557 }
558
559 config_error(c, "Expecting section end while parsing listener");
560}
561
562static bool_Bool setup_from_config(struct lwan *lwan, const char *path)
563{
564 const struct config_line *line;
565 struct config *conf;
566 bool_Bool has_site = false0;
567 bool_Bool has_listener = false0;
568 bool_Bool has_tls_listener = false0;
569 char path_buf[PATH_MAX4096];
570
571 if (!path
3.1
'path' is null
)
4
Taking true branch
572 path = lwan_get_config_path(path_buf, sizeof(path_buf));
573 lwan_status_info("Loading configuration file: %s", path)lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 573, __FUNCTION__, "Loading configuration file: %s", path)
;
574
575 conf = config_open(path);
576 if (!conf)
5
Assuming 'conf' is non-null
6
Taking false branch
577 return false0;
578
579 if (!lwan_trie_init(&lwan->url_map_trie, destroy_urlmap))
7
Assuming the condition is false
8
Taking false branch
580 return false0;
581
582 while ((line = config_read_line(conf))) {
9
Loop condition is true. Entering loop body
583 switch (line->type) {
10
Control jumps to 'case CONFIG_LINE_TYPE_SECTION:' at line 644
584 case CONFIG_LINE_TYPE_LINE:
585 if (streq(line->key, "keep_alive_timeout")) {
586 lwan->config.keep_alive_timeout = (unsigned int)parse_long(
587 line->value, default_config.keep_alive_timeout);
588 } else if (streq(line->key, "quiet")) {
589 lwan->config.quiet =
590 parse_bool(line->value, default_config.quiet);
591 } else if (streq(line->key, "proxy_protocol")) {
592 lwan->config.proxy_protocol =
593 parse_bool(line->value, default_config.proxy_protocol);
594 } else if (streq(line->key, "allow_cors")) {
595 lwan->config.allow_cors =
596 parse_bool(line->value, default_config.allow_cors);
597 } else if (streq(line->key, "expires")) {
598 lwan->config.expires =
599 parse_time_period(line->value, default_config.expires);
600 } else if (streq(line->key, "error_template")) {
601 free(lwan->config.error_template);
602 lwan->config.error_template = strdup(line->value);
603 } else if (streq(line->key, "threads")) {
604 long n_threads =
605 parse_long(line->value, default_config.n_threads);
606 if (n_threads < 0)
607 config_error(conf, "Invalid number of threads: %ld",
608 n_threads);
609 lwan->config.n_threads = (unsigned int)n_threads;
610 } else if (streq(line->key, "max_post_data_size")) {
611 long max_post_data_size = parse_long(
612 line->value, (long)default_config.max_post_data_size);
613 if (max_post_data_size < 0)
614 config_error(conf, "Negative maximum post data size");
615 else if (max_post_data_size > 128 * (1 << 20))
616 config_error(conf,
617 "Maximum post data can't be over 128MiB");
618 lwan->config.max_post_data_size = (size_t)max_post_data_size;
619 } else if (streq(line->key, "max_put_data_size")) {
620 long max_put_data_size = parse_long(
621 line->value, (long)default_config.max_put_data_size);
622 if (max_put_data_size < 0)
623 config_error(conf, "Negative maximum put data size");
624 else if (max_put_data_size > 128 * (1 << 20))
625 config_error(conf,
626 "Maximum put data can't be over 128MiB");
627 lwan->config.max_put_data_size = (size_t)max_put_data_size;
628 } else if (streq(line->key, "allow_temp_files")) {
629 bool_Bool has_post, has_put;
630
631 if (strstr(line->value, "all")) {
632 has_post = has_put = true1;
633 } else {
634 has_post = !!strstr(line->value, "post");
635 has_put = !!strstr(line->value, "put");
636 }
637
638 lwan->config.allow_post_temp_file = has_post;
639 lwan->config.allow_put_temp_file = has_put;
640 } else {
641 config_error(conf, "Unknown config key: %s", line->key);
642 }
643 break;
644 case CONFIG_LINE_TYPE_SECTION:
645 if (streq(line->key, "site")) {
11
Taking true branch
646 if (!has_site
11.1
'has_site' is false
) {
12
Taking true branch
647 parse_site(conf, line, lwan);
13
Calling 'parse_site'
648 has_site = true1;
649 } else {
650 config_error(conf, "Only one site may be configured");
651 }
652 } else if (streq(line->key, "straitjacket")) {
653 lwan_straitjacket_enforce_from_config(conf);
654 } else if (streq(line->key, "headers")) {
655 parse_global_headers(conf, lwan);
656 } else if (streq(line->key, "listener")) {
657 if (has_listener) {
658 config_error(conf, "Listener already set up");
659 } else {
660 parse_listener(conf, line, lwan);
661 has_listener = true1;
662 }
663 } else if (streq(line->key, "tls_listener")) {
664 if (has_tls_listener) {
665 config_error(conf, "TLS Listener already set up");
666 } else {
667 parse_tls_listener(conf, line, lwan);
668 has_tls_listener = true1;
669 }
670 } else {
671 config_error(conf, "Unknown section type: %s", line->key);
672 }
673 break;
674 case CONFIG_LINE_TYPE_SECTION_END:
675 config_error(conf, "Unexpected section end");
676 }
677 }
678
679 if (config_last_error(conf)) {
680 lwan_status_critical("Error on config file \"%s\", line %d: %s", path,lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 681, __FUNCTION__, "Error on config file \"%s\", line %d: %s"
, path, config_cur_line(conf), config_last_error(conf))
681 config_cur_line(conf), config_last_error(conf))lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 681, __FUNCTION__, "Error on config file \"%s\", line %d: %s"
, path, config_cur_line(conf), config_last_error(conf))
;
682 lwan_trie_destroy(&lwan->url_map_trie);
683 }
684
685 config_close(conf);
686
687 return true1;
688}
689
690static void try_setup_from_config(struct lwan *l,
691 const struct lwan_config *config)
692{
693 if (!setup_from_config(l, config->config_file_path)) {
3
Calling 'setup_from_config'
694 if (config->config_file_path) {
695 lwan_status_critical("Could not read config file: %s",lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 696, __FUNCTION__, "Could not read config file: %s", config
->config_file_path)
696 config->config_file_path)lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 696, __FUNCTION__, "Could not read config file: %s", config
->config_file_path)
;
697 }
698 }
699
700 lwan_status_init(l); /* `quiet` key might have changed value. */
701
702 l->config.request_flags =
703 (l->config.proxy_protocol ? REQUEST_ALLOW_PROXY_REQS : 0) |
704 (l->config.allow_cors ? REQUEST_ALLOW_CORS : 0) |
705 (l->config.ssl.send_hsts_header ? REQUEST_WANTS_HSTS_HEADER : 0);
706}
707
708static rlim_t setup_open_file_count_limits(void)
709{
710 struct rlimit r;
711
712 if (getrlimit(RLIMIT_NOFILERLIMIT_NOFILE, &r) < 0) {
713 lwan_status_perror("Could not obtain maximum number of file "lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 715, __FUNCTION__, "Could not obtain maximum number of file "
"descriptors. Assuming %d", 256)
714 "descriptors. Assuming %d",lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 715, __FUNCTION__, "Could not obtain maximum number of file "
"descriptors. Assuming %d", 256)
715 OPEN_MAX)lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 715, __FUNCTION__, "Could not obtain maximum number of file "
"descriptors. Assuming %d", 256)
;
716 return OPEN_MAX256;
717 }
718
719 if (r.rlim_max != r.rlim_cur) {
720 const rlim_t current = r.rlim_cur;
721
722 if (r.rlim_max == RLIM_INFINITY0xffffffffffffffffuLL && r.rlim_cur < OPEN_MAX256) {
723 r.rlim_cur = OPEN_MAX256;
724 } else if (r.rlim_cur < r.rlim_max) {
725 r.rlim_cur = r.rlim_max;
726 } else {
727 /* Shouldn't happen, so just return the current value. */
728 goto out;
729 }
730
731 if (setrlimit(RLIMIT_NOFILERLIMIT_NOFILE, &r) < 0) {
732 lwan_status_perror("Could not raise maximum number of file "lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 734, __FUNCTION__, "Could not raise maximum number of file "
"descriptors to %" "l" "u" ". Leaving at " "%" "l" "u", r.rlim_max
, current)
733 "descriptors to %" PRIu64 ". Leaving at "lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 734, __FUNCTION__, "Could not raise maximum number of file "
"descriptors to %" "l" "u" ". Leaving at " "%" "l" "u", r.rlim_max
, current)
734 "%" PRIu64, r.rlim_max, current)lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 734, __FUNCTION__, "Could not raise maximum number of file "
"descriptors to %" "l" "u" ". Leaving at " "%" "l" "u", r.rlim_max
, current)
;
735 r.rlim_cur = current;
736 }
737 }
738
739out:
740 return r.rlim_cur;
741}
742
743static void allocate_connections(struct lwan *l, size_t max_open_files)
744{
745 const size_t sz = max_open_files * sizeof(struct lwan_connection);
746
747 l->conns = lwan_aligned_alloc(sz, 64);
748 if (UNLIKELY(!l->conns)__builtin_expect(((!l->conns)), (0)))
749 lwan_status_critical_perror("lwan_alloc_aligned")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 749, __FUNCTION__, "lwan_alloc_aligned")
;
750
751 memset(l->conns, 0, sz);
752}
753
754static void get_number_of_cpus(struct lwan *l)
755{
756 long n_online_cpus = sysconf(_SC_NPROCESSORS_ONLN_SC_NPROCESSORS_ONLN);
757 long n_available_cpus = sysconf(_SC_NPROCESSORS_CONF_SC_NPROCESSORS_CONF);
758
759 if (n_online_cpus < 0) {
760 lwan_status_warning(lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 761, __FUNCTION__, "Could not get number of online CPUs, assuming 1 CPU"
)
761 "Could not get number of online CPUs, assuming 1 CPU")lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 761, __FUNCTION__, "Could not get number of online CPUs, assuming 1 CPU"
)
;
762 n_online_cpus = 1;
763 }
764
765 if (n_available_cpus < 0) {
766 lwan_status_warning(lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 768, __FUNCTION__, "Could not get number of available CPUs, assuming %ld CPUs"
, n_online_cpus)
767 "Could not get number of available CPUs, assuming %ld CPUs",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 768, __FUNCTION__, "Could not get number of available CPUs, assuming %ld CPUs"
, n_online_cpus)
768 n_online_cpus)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 768, __FUNCTION__, "Could not get number of available CPUs, assuming %ld CPUs"
, n_online_cpus)
;
769 n_available_cpus = n_online_cpus;
770 }
771
772 l->online_cpus = (unsigned int)n_online_cpus;
773 l->available_cpus = (unsigned int)n_available_cpus;
774}
775
776void lwan_init(struct lwan *l) { lwan_init_with_config(l, &default_config); }
1
Calling 'lwan_init_with_config'
777
778const struct lwan_config *lwan_get_default_config(void)
779{
780 return &default_config;
781}
782
783static char *dup_or_null(const char *s)
784{
785 return s ? strdup(s) : NULL((void*)0);
786}
787
788void lwan_init_with_config(struct lwan *l, const struct lwan_config *config)
789{
790 /* Load defaults */
791 memset(l, 0, sizeof(*l));
792 memcpy(&l->config, config, sizeof(*config));
793 l->config.listener = dup_or_null(l->config.listener);
794 l->config.config_file_path = dup_or_null(l->config.config_file_path);
795 l->config.ssl.key = dup_or_null(l->config.ssl.key);
796 l->config.ssl.cert = dup_or_null(l->config.ssl.cert);
797
798 /* Initialize status first, as it is used by other things during
799 * their initialization. */
800 lwan_status_init(l);
801
802 /* These will only print debugging messages. Debug messages are always
803 * printed if we're on a debug build, so the quiet setting will be
804 * respected. */
805 lwan_job_thread_init();
806 lwan_tables_init();
807
808 /* Get the number of CPUs here because straightjacket might be active
809 * and this will block access to /proc and /sys, which will cause
810 * get_number_of_cpus() to get incorrect fallback values. */
811 get_number_of_cpus(l);
812
813 try_setup_from_config(l, config);
2
Calling 'try_setup_from_config'
814
815 if (!l->headers.len)
816 build_response_headers(l, config->global_headers);
817
818 lwan_response_init(l);
819
820 /* Continue initialization as normal. */
821 lwan_status_debug("Initializing lwan web server")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 821, __FUNCTION__, "Initializing lwan web server")
;
822
823 if (!l->config.n_threads) {
824 l->thread.count = l->online_cpus;
825 if (l->thread.count == 1)
826 l->thread.count = 2;
827 } else if (l->config.n_threads > 3 * l->online_cpus) {
828 l->thread.count = l->online_cpus * 3;
829
830 lwan_status_warning("%d threads requested, but only %d online CPUs "lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 833, __FUNCTION__, "%d threads requested, but only %d online CPUs "
"(out of %d configured CPUs); capping to %d threads", l->
config.n_threads, l->online_cpus, l->available_cpus, 3 *
l->online_cpus)
831 "(out of %d configured CPUs); capping to %d threads",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 833, __FUNCTION__, "%d threads requested, but only %d online CPUs "
"(out of %d configured CPUs); capping to %d threads", l->
config.n_threads, l->online_cpus, l->available_cpus, 3 *
l->online_cpus)
832 l->config.n_threads, l->online_cpus, l->available_cpus,lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 833, __FUNCTION__, "%d threads requested, but only %d online CPUs "
"(out of %d configured CPUs); capping to %d threads", l->
config.n_threads, l->online_cpus, l->available_cpus, 3 *
l->online_cpus)
833 3 * l->online_cpus)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 833, __FUNCTION__, "%d threads requested, but only %d online CPUs "
"(out of %d configured CPUs); capping to %d threads", l->
config.n_threads, l->online_cpus, l->available_cpus, 3 *
l->online_cpus)
;
834 } else if (l->config.n_threads > 255) {
835 l->thread.count = 256;
836
837 lwan_status_warning("%d threads requested, but max 256 supported",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 838, __FUNCTION__, "%d threads requested, but max 256 supported"
, l->config.n_threads)
838 l->config.n_threads)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 838, __FUNCTION__, "%d threads requested, but max 256 supported"
, l->config.n_threads)
;
839 } else {
840 l->thread.count = l->config.n_threads;
841 }
842
843 rlim_t max_open_files = setup_open_file_count_limits();
844 allocate_connections(l, (size_t)max_open_files);
845
846 l->thread.max_fd = (unsigned)max_open_files / (unsigned)l->thread.count;
847 lwan_status_info("Using %d threads, maximum %d sockets per thread",lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 848, __FUNCTION__, "Using %d threads, maximum %d sockets per thread"
, l->thread.count, l->thread.max_fd)
848 l->thread.count, l->thread.max_fd)lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 848, __FUNCTION__, "Using %d threads, maximum %d sockets per thread"
, l->thread.count, l->thread.max_fd)
;
849
850 signal(SIGPIPE13, SIG_IGN((__sighandler_t) 1));
851
852 lwan_readahead_init();
853 lwan_thread_init(l);
854 lwan_http_authorize_init();
855}
856
857void lwan_shutdown(struct lwan *l)
858{
859 lwan_status_info("Shutting down")lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 859, __FUNCTION__, "Shutting down")
;
860
861 free(l->config.listener);
862 free(l->config.error_template);
863 free(l->config.config_file_path);
864
865 lwan_always_bzero(l->config.ssl.cert, strlen(l->config.ssl.cert));
866 free(l->config.ssl.cert);
867 lwan_always_bzero(l->config.ssl.key, strlen(l->config.ssl.key));
868 free(l->config.ssl.key);
869
870 lwan_job_thread_shutdown();
871 lwan_thread_shutdown(l);
872
873 lwan_status_debug("Shutting down URL handlers")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 873, __FUNCTION__, "Shutting down URL handlers")
;
874 lwan_trie_destroy(&l->url_map_trie);
875
876 free(l->headers.value);
877 free(l->conns);
878
879 lwan_response_shutdown(l);
880 lwan_tables_shutdown();
881 lwan_status_shutdown(l);
882 lwan_http_authorize_shutdown();
883 lwan_readahead_shutdown();
884}
885
886void lwan_main_loop(struct lwan *l)
887{
888 lwan_status_info("Ready to serve")lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 888, __FUNCTION__, "Ready to serve")
;
889
890 lwan_job_thread_main_loop();
891}
892
893#ifdef CLOCK_MONOTONIC_COARSE6
894__attribute__((constructor)) static void detect_fastest_monotonic_clock(void)
895{
896 struct timespec ts;
897
898 if (!clock_gettime(CLOCK_MONOTONIC_COARSE6, &ts))
899 monotonic_clock_id = CLOCK_MONOTONIC_COARSE6;
900}
901#endif
902
903void lwan_set_thread_name(const char *name)
904{
905 char thread_name[16];
906 char process_name[PATH_MAX4096];
907 char *tmp;
908 int ret;
909
910 if (proc_pidpath(getpid(), process_name, sizeof(process_name)) < 0)
911 return;
912
913 tmp = strrchr(process_name, '/');
914 if (!tmp)
915 return;
916
917 ret = snprintf(thread_name, sizeof(thread_name), "%s %s", tmp + 1, name);
918 if (ret < 0)
919 return;
920
921 pthread_set_name_np(pthread_self(), thread_name);
922}