Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -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 -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -fno-plt -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/clang/9.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.0 -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/local/include -internal-isystem /usr/lib/clang/9.0.1/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 -fmessage-length 0 -stack-protector 2 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -faddrsig -o /home/buildbot/lwan-worker/clang-analyze/CLANG/2020-02-15-042808-2900692-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 Leandro A. F. Pereira <leandro@hardinfo.org>
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/* See detect_fastest_monotonic_clock() */
47clockid_t monotonic_clock_id = CLOCK_MONOTONIC1;
48
49static const struct lwan_config default_config = {
50 .listener = "localhost:8080",
51 .keep_alive_timeout = 15,
52 .quiet = false0,
53 .reuse_port = false0,
54 .proxy_protocol = false0,
55 .allow_cors = false0,
56 .expires = 1 * ONE_WEEK(((60 * 60) * 24) * 7),
57 .n_threads = 0,
58 .max_post_data_size = 10 * DEFAULT_BUFFER_SIZE4096,
59 .allow_post_temp_file = false0,
60};
61
62LWAN_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)))
63{
64 /* Placeholder handler so that __start_lwan_handler and __stop_lwan_handler
65 * symbols will get defined.
66 */
67 return HTTP_I_AM_A_TEAPOT;
68}
69
70__attribute__((no_sanitize_address))
71static void *find_handler(const char *name)
72{
73 const struct lwan_handler_info *handler;
74
75 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
)++)
{
76 if (streq(handler->name, name))
77 return handler->handler;
78 }
79
80 return NULL((void*)0);
81}
82
83__attribute__((no_sanitize_address))
84static const struct lwan_module *find_module(const char *name)
85{
86 const struct lwan_module_info *module;
87
88 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
)++)
{
89 if (streq(module->name, name))
90 return module->module;
91 }
92
93 return NULL((void*)0);
94}
95
96static void destroy_urlmap(void *data)
97{
98 struct lwan_url_map *url_map = data;
99
100 if (url_map->module) {
101 const struct lwan_module *module = url_map->module;
102
103 if (module->destroy)
104 module->destroy(url_map->data);
105 } else if (url_map->data && url_map->flags & HANDLER_DATA_IS_HASH_TABLE) {
106 hash_free(url_map->data);
107 }
108
109 free(url_map->authorization.realm);
110 free(url_map->authorization.password_file);
111 free((char *)url_map->prefix);
112 free(url_map);
113}
114
115static struct lwan_url_map *add_url_map(struct lwan_trie *t, const char *prefix,
116 const struct lwan_url_map *map)
117{
118 struct lwan_url_map *copy = malloc(sizeof(*copy));
119
120 if (!copy)
121 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"
, 121, __FUNCTION__, "Could not copy URL map")
;
122
123 memcpy(copy, map, sizeof(*copy));
124
125 copy->prefix = strdup(prefix ? prefix : copy->prefix);
126 if (!copy->prefix)
127 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"
, 127, __FUNCTION__, "Could not copy URL prefix")
;
128
129 copy->prefix_len = strlen(copy->prefix);
130 lwan_trie_add(t, copy->prefix, copy);
131
132 return copy;
133}
134
135static void parse_listener_prefix_authorization(struct config *c,
136 const struct config_line *l,
137 struct lwan_url_map *url_map)
138{
139 if (!streq(l->value, "basic")) {
140 config_error(c, "Only basic authorization supported");
141 return;
142 }
143
144 memset(&url_map->authorization, 0, sizeof(url_map->authorization));
145
146 while ((l = config_read_line(c))) {
147 switch (l->type) {
148 case CONFIG_LINE_TYPE_LINE:
149 if (streq(l->key, "realm")) {
150 free(url_map->authorization.realm);
151 url_map->authorization.realm = strdup(l->value);
152 } else if (streq(l->key, "password_file")) {
153 free(url_map->authorization.password_file);
154 url_map->authorization.password_file = realpath(l->value, NULL((void*)0));
155 if (!url_map->authorization.password_file)
156 config_error(c, "Could not determine full path for password file: %s", l->value);
157 }
158 break;
159
160 case CONFIG_LINE_TYPE_SECTION:
161 config_error(c, "Unexpected section: %s", l->key);
162 goto error;
163
164 case CONFIG_LINE_TYPE_SECTION_END:
165 if (!url_map->authorization.realm)
166 url_map->authorization.realm = strdup("Lwan");
167 if (!url_map->authorization.password_file)
168 url_map->authorization.password_file = strdup("htpasswd");
169
170 url_map->flags |= HANDLER_MUST_AUTHORIZE;
171 return;
172 }
173 }
174
175 config_error(c, "Could not find end of authorization section");
176
177error:
178 free(url_map->authorization.realm);
179 free(url_map->authorization.password_file);
180}
181
182static void parse_listener_prefix(struct config *c,
183 const struct config_line *l,
184 struct lwan *lwan,
185 const struct lwan_module *module,
186 void *handler)
187{
188 struct lwan_url_map url_map = {};
189 struct hash *hash = hash_str_new(free, free);
190 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); }))
;
191 struct config *isolated;
192
193 isolated = config_isolate_section(c, l);
194 if (!isolated) {
21
Assuming 'isolated' is non-null
22
Taking false branch
195 config_error(c, "Could not isolate configuration file");
196 goto out;
197 }
198
199 while ((l = config_read_line(c))) {
23
Loop condition is true. Entering loop body
27
Potential memory leak
200 switch (l->type) {
24
Control jumps to 'case CONFIG_LINE_TYPE_LINE:' at line 201
201 case CONFIG_LINE_TYPE_LINE:
202 hash_add(hash, strdup(l->key), strdup(l->value));
25
Memory is allocated
203 break;
26
Execution continues on line 199
204
205 case CONFIG_LINE_TYPE_SECTION:
206 if (streq(l->key, "authorization")) {
207 parse_listener_prefix_authorization(c, l, &url_map);
208 } else if (!config_skip_section(c, l)) {
209 config_error(c, "Could not skip section");
210 goto out;
211 }
212 break;
213
214 case CONFIG_LINE_TYPE_SECTION_END:
215 goto add_map;
216 }
217 }
218
219 config_error(c, "Expecting section end while parsing prefix");
220 goto out;
221
222add_map:
223 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"
, 223, __extension__ __PRETTY_FUNCTION__); }))
;
224
225 if (handler) {
226 url_map.handler = handler;
227 url_map.flags |= HANDLER_PARSE_MASK | HANDLER_DATA_IS_HASH_TABLE;
228 url_map.data = hash;
229 url_map.module = NULL((void*)0);
230
231 hash = NULL((void*)0);
232 } else if (module->create_from_hash && module->handle_request) {
233 url_map.data = module->create_from_hash(prefix, hash);
234 if (!url_map.data) {
235 config_error(c, "Could not create module instance");
236 goto out;
237 }
238
239 if (module->parse_conf && !module->parse_conf(url_map.data, isolated)) {
240 const char *msg = config_last_error(isolated);
241
242 config_error(c, "Error from module: %s", msg ? msg : "Unknown");
243 goto out;
244 }
245
246 url_map.handler = module->handle_request;
247 url_map.flags |= module->flags;
248 url_map.module = module;
249 } else if (UNLIKELY(!module->create_from_hash)__builtin_expect(((!module->create_from_hash)), (0))) {
250 config_error(c, "Module isn't prepared to load settings from a file; "
251 "create_from_hash() method isn't present");
252 goto out;
253 } else if (UNLIKELY(!module->handle_request)__builtin_expect(((!module->handle_request)), (0))) {
254 config_error(c, "Module does not have handle_request() method");
255 goto out;
256 }
257
258 add_url_map(&lwan->url_map_trie, prefix, &url_map);
259
260out:
261 hash_free(hash);
262 config_close(isolated);
263}
264
265void lwan_set_url_map(struct lwan *l, const struct lwan_url_map *map)
266{
267 lwan_trie_destroy(&l->url_map_trie);
268 if (UNLIKELY(!lwan_trie_init(&l->url_map_trie, destroy_urlmap))__builtin_expect(((!lwan_trie_init(&l->url_map_trie, destroy_urlmap
))), (0))
)
269 lwan_status_critical_perror("Could not initialize trie")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 269, __FUNCTION__, "Could not initialize trie")
;
270
271 for (; map->prefix; map++) {
272 struct lwan_url_map *copy = add_url_map(&l->url_map_trie, NULL((void*)0), map);
273
274 if (copy->module && copy->module->create) {
275 copy->data = copy->module->create (map->prefix, copy->args);
276 copy->flags = copy->module->flags;
277 copy->handler = copy->module->handle_request;
278 } else {
279 copy->flags = HANDLER_PARSE_MASK;
280 }
281 }
282}
283
284static void parse_listener(struct config *c,
285 const struct config_line *l,
286 struct lwan *lwan)
287{
288 free(lwan->config.listener);
289 lwan->config.listener = strdup(l->value);
290
291 while ((l = config_read_line(c))) {
14
Loop condition is true. Entering loop body
292 switch (l->type) {
15
Control jumps to 'case CONFIG_LINE_TYPE_SECTION:' at line 296
293 case CONFIG_LINE_TYPE_LINE:
294 config_error(c, "Expecting prefix section");
295 return;
296 case CONFIG_LINE_TYPE_SECTION:
297 if (l->key[0] == '&') {
16
Assuming the condition is true
17
Taking true branch
298 void *handler = find_handler(l->key + 1);
299 if (handler) {
18
Assuming 'handler' is non-null
19
Taking true branch
300 parse_listener_prefix(c, l, lwan, NULL((void*)0), handler);
20
Calling 'parse_listener_prefix'
301 continue;
302 }
303
304 config_error(c, "Could not find handler name: %s", l->key + 1);
305 return;
306 }
307
308 const struct lwan_module *module = find_module(l->key);
309 if (module) {
310 parse_listener_prefix(c, l, lwan, module, NULL((void*)0));
311 continue;
312 }
313
314 config_error(c, "Invalid section or module not found: %s", l->key);
315 return;
316 case CONFIG_LINE_TYPE_SECTION_END:
317 return;
318 }
319 }
320
321 config_error(c, "Expecting section end while parsing listener");
322}
323
324const char *lwan_get_config_path(char *path_buf, size_t path_buf_len)
325{
326 char buffer[PATH_MAX4096];
327
328 if (proc_pidpath(getpid(), buffer, sizeof(buffer)) < 0)
329 goto out;
330
331 char *path = strrchr(buffer, '/');
332 if (!path)
333 goto out;
334 int ret = snprintf(path_buf, path_buf_len, "%s.conf", path + 1);
335 if (ret < 0 || ret >= (int)path_buf_len)
336 goto out;
337
338 return path_buf;
339
340out:
341 return "lwan.conf";
342}
343
344static bool_Bool setup_from_config(struct lwan *lwan, const char *path)
345{
346 const struct config_line *line;
347 struct config *conf;
348 bool_Bool has_listener = false0;
349 char path_buf[PATH_MAX4096];
350
351 if (!
3.1
'path' is null
path)
4
Taking true branch
352 path = lwan_get_config_path(path_buf, sizeof(path_buf));
353 lwan_status_info("Loading configuration file: %s", path)lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 353, __FUNCTION__, "Loading configuration file: %s", path)
;
354
355 conf = config_open(path);
356 if (!conf)
5
Assuming 'conf' is non-null
6
Taking false branch
357 return false0;
358
359 if (!lwan_trie_init(&lwan->url_map_trie, destroy_urlmap))
7
Assuming the condition is false
8
Taking false branch
360 return false0;
361
362 while ((line = config_read_line(conf))) {
9
Loop condition is true. Entering loop body
363 switch (line->type) {
10
Control jumps to 'case CONFIG_LINE_TYPE_SECTION:' at line 409
364 case CONFIG_LINE_TYPE_LINE:
365 if (streq(line->key, "keep_alive_timeout")) {
366 lwan->config.keep_alive_timeout = (unsigned short)parse_long(
367 line->value, default_config.keep_alive_timeout);
368 } else if (streq(line->key, "quiet")) {
369 lwan->config.quiet =
370 parse_bool(line->value, default_config.quiet);
371 } else if (streq(line->key, "reuse_port")) {
372 lwan->config.reuse_port =
373 parse_bool(line->value, default_config.reuse_port);
374 } else if (streq(line->key, "proxy_protocol")) {
375 lwan->config.proxy_protocol =
376 parse_bool(line->value, default_config.proxy_protocol);
377 } else if (streq(line->key, "allow_cors")) {
378 lwan->config.allow_cors =
379 parse_bool(line->value, default_config.allow_cors);
380 } else if (streq(line->key, "expires")) {
381 lwan->config.expires =
382 parse_time_period(line->value, default_config.expires);
383 } else if (streq(line->key, "error_template")) {
384 free(lwan->config.error_template);
385 lwan->config.error_template = strdup(line->value);
386 } else if (streq(line->key, "threads")) {
387 long n_threads =
388 parse_long(line->value, default_config.n_threads);
389 if (n_threads < 0)
390 config_error(conf, "Invalid number of threads: %ld",
391 n_threads);
392 lwan->config.n_threads = (unsigned short int)n_threads;
393 } else if (streq(line->key, "max_post_data_size")) {
394 long max_post_data_size = parse_long(
395 line->value, (long)default_config.max_post_data_size);
396 if (max_post_data_size < 0)
397 config_error(conf, "Negative maximum post data size");
398 else if (max_post_data_size > 128 * (1 << 20))
399 config_error(conf,
400 "Maximum post data can't be over 128MiB");
401 lwan->config.max_post_data_size = (size_t)max_post_data_size;
402 } else if (streq(line->key, "allow_temp_files")) {
403 lwan->config.allow_post_temp_file =
404 !!strstr(line->value, "post");
405 } else {
406 config_error(conf, "Unknown config key: %s", line->key);
407 }
408 break;
409 case CONFIG_LINE_TYPE_SECTION:
410 if (streq(line->key, "listener")) {
11
Taking true branch
411 if (!
11.1
'has_listener' is false
has_listener) {
12
Taking true branch
412 parse_listener(conf, line, lwan);
13
Calling 'parse_listener'
413 has_listener = true1;
414 } else {
415 config_error(conf, "Only one listener supported");
416 }
417 } else if (streq(line->key, "straitjacket")) {
418 lwan_straitjacket_enforce_from_config(conf);
419 } else {
420 config_error(conf, "Unknown section type: %s", line->key);
421 }
422 break;
423 case CONFIG_LINE_TYPE_SECTION_END:
424 config_error(conf, "Unexpected section end");
425 }
426 }
427
428 if (config_last_error(conf)) {
429 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"
, 430, __FUNCTION__, "Error on config file \"%s\", line %d: %s"
, path, config_cur_line(conf), config_last_error(conf))
430 config_cur_line(conf), config_last_error(conf))lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 430, __FUNCTION__, "Error on config file \"%s\", line %d: %s"
, path, config_cur_line(conf), config_last_error(conf))
;
431 }
432
433 config_close(conf);
434
435 return true1;
436}
437
438static void try_setup_from_config(struct lwan *l,
439 const struct lwan_config *config)
440{
441 if (!setup_from_config(l, config->config_file_path)) {
3
Calling 'setup_from_config'
442 if (config->config_file_path) {
443 lwan_status_critical("Could not read config file: %s",lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 444, __FUNCTION__, "Could not read config file: %s", config
->config_file_path)
444 config->config_file_path)lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 444, __FUNCTION__, "Could not read config file: %s", config
->config_file_path)
;
445 }
446 }
447
448 lwan_status_init(l); /* `quiet` key might have changed value. */
449
450 l->config.request_flags =
451 (l->config.proxy_protocol ? REQUEST_ALLOW_PROXY_REQS : 0) |
452 (l->config.allow_cors ? REQUEST_ALLOW_CORS : 0);
453}
454
455static rlim_t setup_open_file_count_limits(void)
456{
457 struct rlimit r;
458
459 if (getrlimit(RLIMIT_NOFILERLIMIT_NOFILE, &r) < 0) {
460 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"
, 462, __FUNCTION__, "Could not obtain maximum number of file "
"descriptors. Assuming %d", 256)
461 "descriptors. Assuming %d",lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 462, __FUNCTION__, "Could not obtain maximum number of file "
"descriptors. Assuming %d", 256)
462 OPEN_MAX)lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 462, __FUNCTION__, "Could not obtain maximum number of file "
"descriptors. Assuming %d", 256)
;
463 return OPEN_MAX256;
464 }
465
466 if (r.rlim_max != r.rlim_cur) {
467 const rlim_t current = r.rlim_cur;
468
469 if (r.rlim_max == RLIM_INFINITY0xffffffffffffffffuLL && r.rlim_cur < OPEN_MAX256) {
470 r.rlim_cur = OPEN_MAX256;
471 } else if (r.rlim_cur < r.rlim_max) {
472 r.rlim_cur = r.rlim_max;
473 } else {
474 /* Shouldn't happen, so just return the current value. */
475 goto out;
476 }
477
478 if (setrlimit(RLIMIT_NOFILERLIMIT_NOFILE, &r) < 0) {
479 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"
, 481, __FUNCTION__, "Could not raise maximum number of file "
"descriptors to %" "l" "u" ". Leaving at " "%" "l" "u", r.rlim_max
, current)
480 "descriptors to %" PRIu64 ". Leaving at "lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 481, __FUNCTION__, "Could not raise maximum number of file "
"descriptors to %" "l" "u" ". Leaving at " "%" "l" "u", r.rlim_max
, current)
481 "%" PRIu64, r.rlim_max, current)lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 481, __FUNCTION__, "Could not raise maximum number of file "
"descriptors to %" "l" "u" ". Leaving at " "%" "l" "u", r.rlim_max
, current)
;
482 r.rlim_cur = current;
483 }
484 }
485
486out:
487 return r.rlim_cur;
488}
489
490static void allocate_connections(struct lwan *l, size_t max_open_files)
491{
492 const size_t sz = max_open_files * sizeof(struct lwan_connection);
493
494 l->conns = lwan_aligned_alloc(sz, 64);
495 if (UNLIKELY(!l->conns)__builtin_expect(((!l->conns)), (0)))
496 lwan_status_critical_perror("lwan_alloc_aligned")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 496, __FUNCTION__, "lwan_alloc_aligned")
;
497
498 memset(l->conns, 0, sz);
499}
500
501static unsigned short int get_number_of_cpus(void)
502{
503 long n_online_cpus = sysconf(_SC_NPROCESSORS_ONLN_SC_NPROCESSORS_ONLN);
504 if (UNLIKELY(n_online_cpus < 0)__builtin_expect(((n_online_cpus < 0)), (0))) {
505 lwan_status_warning(lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 506, __FUNCTION__, "Could not get number of online CPUs, assuming 1 CPU"
)
506 "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"
, 506, __FUNCTION__, "Could not get number of online CPUs, assuming 1 CPU"
)
;
507 return 1;
508 }
509 return (unsigned short int)n_online_cpus;
510}
511
512void lwan_init(struct lwan *l) { lwan_init_with_config(l, &default_config); }
1
Calling 'lwan_init_with_config'
513
514const struct lwan_config *lwan_get_default_config(void)
515{
516 return &default_config;
517}
518
519static char *dup_or_null(const char *s)
520{
521 return s ? strdup(s) : NULL((void*)0);
522}
523
524void lwan_init_with_config(struct lwan *l, const struct lwan_config *config)
525{
526 /* Load defaults */
527 memset(l, 0, sizeof(*l));
528 memcpy(&l->config, config, sizeof(*config));
529 l->config.listener = dup_or_null(l->config.listener);
530 l->config.config_file_path = dup_or_null(l->config.config_file_path);
531
532 /* Initialize status first, as it is used by other things during
533 * their initialization. */
534 lwan_status_init(l);
535
536 /* These will only print debugging messages. Debug messages are always
537 * printed if we're on a debug build, so the quiet setting will be
538 * respected. */
539 lwan_job_thread_init();
540 lwan_tables_init();
541
542 try_setup_from_config(l, config);
2
Calling 'try_setup_from_config'
543
544 lwan_response_init(l);
545
546 /* Continue initialization as normal. */
547 lwan_status_debug("Initializing lwan web server")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 547, __FUNCTION__, "Initializing lwan web server")
;
548
549 l->n_cpus = get_number_of_cpus();
550 if (!l->config.n_threads) {
551 l->thread.count = l->n_cpus;
552 if (l->thread.count == 1)
553 l->thread.count = 2;
554 } else if (l->config.n_threads > 3 * l->n_cpus) {
555 l->thread.count = (short unsigned int)(l->n_cpus * 3);
556
557 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"
, 559, __FUNCTION__, "%d threads requested, but only %d online CPUs; "
"capping to %d threads", l->config.n_threads, l->n_cpus
, 3 * l->n_cpus)
558 "capping to %d threads",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 559, __FUNCTION__, "%d threads requested, but only %d online CPUs; "
"capping to %d threads", l->config.n_threads, l->n_cpus
, 3 * l->n_cpus)
559 l->config.n_threads, l->n_cpus, 3 * l->n_cpus)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 559, __FUNCTION__, "%d threads requested, but only %d online CPUs; "
"capping to %d threads", l->config.n_threads, l->n_cpus
, 3 * l->n_cpus)
;
560 } else if (l->config.n_threads > 255) {
561 l->thread.count = 256;
562
563 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"
, 564, __FUNCTION__, "%d threads requested, but max 256 supported"
, l->config.n_threads)
564 l->config.n_threads)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 564, __FUNCTION__, "%d threads requested, but max 256 supported"
, l->config.n_threads)
;
565 } else {
566 l->thread.count = l->config.n_threads;
567 }
568
569 rlim_t max_open_files = setup_open_file_count_limits();
570 allocate_connections(l, (size_t)max_open_files);
571
572 l->thread.max_fd = (unsigned)max_open_files / (unsigned)l->thread.count;
573 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"
, 574, __FUNCTION__, "Using %d threads, maximum %d sockets per thread"
, l->thread.count, l->thread.max_fd)
574 l->thread.count, l->thread.max_fd)lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 574, __FUNCTION__, "Using %d threads, maximum %d sockets per thread"
, l->thread.count, l->thread.max_fd)
;
575
576 signal(SIGPIPE13, SIG_IGN((__sighandler_t) 1));
577
578 lwan_readahead_init();
579 lwan_thread_init(l);
580 lwan_socket_init(l);
581 lwan_http_authorize_init();
582}
583
584void lwan_shutdown(struct lwan *l)
585{
586 lwan_status_info("Shutting down")lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 586, __FUNCTION__, "Shutting down")
;
587
588 free(l->config.listener);
589 free(l->config.error_template);
590 free(l->config.config_file_path);
591
592 lwan_job_thread_shutdown();
593 lwan_thread_shutdown(l);
594
595 lwan_status_debug("Shutting down URL handlers")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 595, __FUNCTION__, "Shutting down URL handlers")
;
596 lwan_trie_destroy(&l->url_map_trie);
597
598 free(l->conns);
599
600 lwan_response_shutdown(l);
601 lwan_tables_shutdown();
602 lwan_status_shutdown(l);
603 lwan_http_authorize_shutdown();
604 lwan_readahead_shutdown();
605}
606
607static ALWAYS_INLINEinline __attribute__((always_inline)) int schedule_client(struct lwan *l, int fd)
608{
609 struct lwan_thread *thread = l->conns[fd].thread;
610
611 lwan_thread_add_client(thread, fd);
612
613 return (int)(thread - l->thread.threads);
614}
615
616static volatile sig_atomic_t main_socket = -1;
617
618static_assert(sizeof(main_socket) >= sizeof(int),extern int (*__Static_assert_function (void)) [!!sizeof (struct
{ int __error_if_negative: (sizeof(main_socket) >= sizeof
(int)) ? 2 : -1; })]
619 "size of sig_atomic_t > size of int")extern int (*__Static_assert_function (void)) [!!sizeof (struct
{ int __error_if_negative: (sizeof(main_socket) >= sizeof
(int)) ? 2 : -1; })]
;
620
621static void sigint_handler(int signal_number __attribute__((unused)))
622{
623 if (main_socket < 0)
624 return;
625
626 shutdown((int)main_socket, SHUT_RDWRSHUT_RDWR);
627 close((int)main_socket);
628
629 main_socket = -1;
630}
631
632enum herd_accept { HERD_MORE = 0, HERD_GONE = -1, HERD_SHUTDOWN = 1 };
633
634struct core_bitmap {
635 uint64_t bitmap[4];
636};
637
638static ALWAYS_INLINEinline __attribute__((always_inline)) enum herd_accept
639accept_one(struct lwan *l, struct core_bitmap *cores)
640{
641 int fd = accept4((int)main_socket, NULL((void*)0), NULL((void*)0), SOCK_NONBLOCKSOCK_NONBLOCK | SOCK_CLOEXECSOCK_CLOEXEC);
642
643 if (LIKELY(fd >= 0)__builtin_expect((!!(fd >= 0)), (1))) {
644 int core = schedule_client(l, fd);
645
646 cores->bitmap[core / 64] |= UINT64_C(1)1UL<<(core % 64);
647
648 return HERD_MORE;
649 }
650
651 switch (errno(*__errno_location ())) {
652 case EAGAIN11:
653 return HERD_GONE;
654
655 case EBADF9:
656 case ECONNABORTED103:
657 case EINVAL22:
658 if (main_socket < 0) {
659 lwan_status_info("Signal 2 (Interrupt) received")lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 659, __FUNCTION__, "Signal 2 (Interrupt) received")
;
660 } else {
661 lwan_status_info("Main socket closed for unknown reasons")lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 661, __FUNCTION__, "Main socket closed for unknown reasons"
)
;
662 }
663 return HERD_SHUTDOWN;
664
665 default:
666 lwan_status_perror("accept")lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 666, __FUNCTION__, "accept")
;
667 return HERD_MORE;
668 }
669}
670
671void lwan_main_loop(struct lwan *l)
672{
673 struct core_bitmap cores = {};
674
675 assert(main_socket == -1)((void) sizeof ((main_socket == -1) ? 1 : 0), __extension__ (
{ if (main_socket == -1) ; else __assert_fail ("main_socket == -1"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 675, __extension__ __PRETTY_FUNCTION__); }))
;
676 main_socket = l->main_socket;
677
678 if (signal(SIGINT2, sigint_handler) == SIG_ERR((__sighandler_t) -1))
679 lwan_status_critical("Could not set signal handler")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 679, __FUNCTION__, "Could not set signal handler")
;
680
681 lwan_status_info("Ready to serve")lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c"
, 681, __FUNCTION__, "Ready to serve")
;
682
683 while (true1) {
684 enum herd_accept ha;
685
686 fcntl(l->main_socket, F_SETFL4, 0);
687 ha = accept_one(l, &cores);
688 if (ha == HERD_MORE) {
689 fcntl(l->main_socket, F_SETFL4, O_NONBLOCK04000);
690
691 do {
692 ha = accept_one(l, &cores);
693 } while (ha == HERD_MORE);
694 }
695
696 if (UNLIKELY(ha > HERD_MORE)__builtin_expect(((ha > HERD_MORE)), (0)))
697 break;
698
699 for (size_t i = 0; i < N_ELEMENTS(cores.bitmap)(sizeof(cores.bitmap) / sizeof(cores.bitmap[0])); i++) {
700 for (uint64_t c = cores.bitmap[i]; c; c ^= c & -c) {
701 size_t core = (size_t)__builtin_ctzl(c);
702 lwan_thread_nudge(&l->thread.threads[i * 64 + core]);
703 }
704 }
705 cores = (struct core_bitmap){};
706 }
707}
708
709#ifdef CLOCK_MONOTONIC_COARSE6
710__attribute__((constructor)) static void detect_fastest_monotonic_clock(void)
711{
712 struct timespec ts;
713
714 if (!clock_gettime(CLOCK_MONOTONIC_COARSE6, &ts))
715 monotonic_clock_id = CLOCK_MONOTONIC_COARSE6;
716}
717#endif
718
719void lwan_set_thread_name(const char *name)
720{
721 char thread_name[16];
722 char process_name[PATH_MAX4096];
723 char *tmp;
724 int ret;
725
726 if (proc_pidpath(getpid(), process_name, sizeof(process_name)) < 0)
727 return;
728
729 tmp = strrchr(process_name, '/');
730 if (!tmp)
731 return;
732
733 ret = snprintf(thread_name, sizeof(thread_name), "%s %s", tmp + 1, name);
734 if (ret < 0)
735 return;
736
737 pthread_set_name_np(pthread_self(), thread_name);
738}