Bug Summary

File:lib/lwan-config.c
Warning:line 827, column 17
Potential leak of memory pointed to by 'v'

Annotated Source Code

Press '?' to see keyboard shortcuts

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 lwan-config.c -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 -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/lib -resource-dir /usr/lib/clang/17 -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 /home/buildbot/lwan-worker/clang-analyze/build -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/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/13.2.1/../../../../x86_64-pc-linux-gnu/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-override-init -Wno-unused-parameter -Wno-free-nonheap-object -std=gnu11 -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/2024-04-24-020522-2059506-1 -x c /home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c
1/*
2 * lwan - web server
3 * Copyright (c) 2017 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, USA.
18 */
19
20#define _GNU_SOURCE
21
22#include <ctype.h>
23#include <errno(*__errno_location ()).h>
24#include <fcntl.h>
25#include <stdarg.h>
26#include <stdbool.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/mman.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <unistd.h>
34
35#include "lwan-private.h"
36#include "lwan-status.h"
37#include "lwan-config.h"
38#include "lwan-strbuf.h"
39
40#include "ringbuffer.h"
41
42#define LEX_ERROR(lexer, fmt, ...)({ config_error(config_from_lexer(lexer), "%s" fmt, "Syntax error: "
, ...); ((void*)0); })
\
43 ({ \
44 config_error(config_from_lexer(lexer), "%s" fmt, \
45 "Syntax error: ", ##__VA_ARGS__); \
46 NULL((void*)0); \
47 })
48
49#define PARSER_ERROR(parser, fmt, ...)({ config_error(config_from_parser(parser), "%s" fmt, "Parsing error: "
, ...); ((void*)0); })
\
50 ({ \
51 config_error(config_from_parser(parser), "%s" fmt, \
52 "Parsing error: ", ##__VA_ARGS__); \
53 NULL((void*)0); \
54 })
55
56#define INTERNAL_ERROR(parser, fmt, ...)({ config_error(config_from_parser(parser), "%s" fmt, "Internal error: "
, ...); ((void*)0); })
\
57 ({ \
58 config_error(config_from_parser(parser), "%s" fmt, \
59 "Internal error: ", ##__VA_ARGS__); \
60 NULL((void*)0); \
61 })
62
63#define FOR_EACH_LEXEME(X)X(STRING) X(EQUAL) X(OPEN_BRACKET) X(CLOSE_BRACKET) X(LINEFEED
) X(VARIABLE) X(VARIABLE_DEFAULT) X((-1))
\
64 X(STRING) X(EQUAL) X(OPEN_BRACKET) X(CLOSE_BRACKET) X(LINEFEED) X(VARIABLE) \
65 X(VARIABLE_DEFAULT) X(EOF(-1))
66
67#define GENERATE_ENUM(id) LEXEME_ ## id,
68
69enum lexeme_type {
70 FOR_EACH_LEXEME(GENERATE_ENUM)GENERATE_ENUM(STRING) GENERATE_ENUM(EQUAL) GENERATE_ENUM(OPEN_BRACKET
) GENERATE_ENUM(CLOSE_BRACKET) GENERATE_ENUM(LINEFEED) GENERATE_ENUM
(VARIABLE) GENERATE_ENUM(VARIABLE_DEFAULT) GENERATE_ENUM((-1)
)
71 TOTAL_LEXEMES
72};
73
74#undef GENERATE_ENUM
75
76struct lexeme {
77 enum lexeme_type type;
78 struct {
79 const char *value;
80 size_t len;
81 } value;
82};
83
84DEFINE_RING_BUFFER_TYPE(lexeme_ring_buffer, struct lexeme, 4)_Static_assert((4) && !((4) & ((4)-1)), "size is a power of two"
); struct lexeme_ring_buffer { uint32_t read, write; struct lexeme
array[4]; }; __attribute__((unused)) static inline uint32_t lexeme_ring_buffer_mask
( uint32_t value) { return value & ((4)-1); } __attribute__
((unused)) static inline uint32_t lexeme_ring_buffer_size( const
struct lexeme_ring_buffer *rb) { return rb->write - rb->
read; } __attribute__((unused)) static inline _Bool lexeme_ring_buffer_full
( const struct lexeme_ring_buffer *rb) { return lexeme_ring_buffer_size
(rb) == (4); } __attribute__((unused)) static inline _Bool lexeme_ring_buffer_empty
( const struct lexeme_ring_buffer *rb) { return rb->write ==
rb->read; } __attribute__((unused)) static inline void lexeme_ring_buffer_init
( struct lexeme_ring_buffer *rb) { rb->write = rb->read
= 0; } __attribute__((unused)) static inline void lexeme_ring_buffer_put
( struct lexeme_ring_buffer *rb, const struct lexeme *e) { ((
void) sizeof ((!lexeme_ring_buffer_full(rb)) ? 1 : 0), __extension__
({ if (!lexeme_ring_buffer_full(rb)) ; else __assert_fail ("!lexeme_ring_buffer_full(rb)"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 84, __extension__ __PRETTY_FUNCTION__); })); memcpy(&rb
->array[lexeme_ring_buffer_mask(rb->write++)], e, sizeof
(*e)); } __attribute__((unused)) static inline _Bool lexeme_ring_buffer_try_put
( struct lexeme_ring_buffer *rb, const struct lexeme *e) { if
(lexeme_ring_buffer_full(rb)) return 0; memcpy(&rb->array
[lexeme_ring_buffer_mask(rb->write++)], e, sizeof(*e)); return
1; } __attribute__((unused)) static inline struct lexeme lexeme_ring_buffer_get
( struct lexeme_ring_buffer *rb) { ((void) sizeof ((!lexeme_ring_buffer_empty
(rb)) ? 1 : 0), __extension__ ({ if (!lexeme_ring_buffer_empty
(rb)) ; else __assert_fail ("!lexeme_ring_buffer_empty(rb)", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 84, __extension__ __PRETTY_FUNCTION__); })); return rb->
array[lexeme_ring_buffer_mask(rb->read++)]; } __attribute__
((unused)) static inline struct lexeme *lexeme_ring_buffer_get_ptr
( struct lexeme_ring_buffer *rb) { ((void) sizeof ((!lexeme_ring_buffer_empty
(rb)) ? 1 : 0), __extension__ ({ if (!lexeme_ring_buffer_empty
(rb)) ; else __assert_fail ("!lexeme_ring_buffer_empty(rb)", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 84, __extension__ __PRETTY_FUNCTION__); })); return &rb
->array[lexeme_ring_buffer_mask(rb->read++)]; } __attribute__
((unused)) static inline struct lexeme *lexeme_ring_buffer_get_ptr_or_null
(struct lexeme_ring_buffer *rb) { return lexeme_ring_buffer_empty
(rb) ? ((void*)0) : &rb->array[lexeme_ring_buffer_mask
(rb->read++)]; }
85DEFINE_RING_BUFFER_TYPE(config_ring_buffer, struct config_line, 4)_Static_assert((4) && !((4) & ((4)-1)), "size is a power of two"
); struct config_ring_buffer { uint32_t read, write; struct config_line
array[4]; }; __attribute__((unused)) static inline uint32_t config_ring_buffer_mask
( uint32_t value) { return value & ((4)-1); } __attribute__
((unused)) static inline uint32_t config_ring_buffer_size( const
struct config_ring_buffer *rb) { return rb->write - rb->
read; } __attribute__((unused)) static inline _Bool config_ring_buffer_full
( const struct config_ring_buffer *rb) { return config_ring_buffer_size
(rb) == (4); } __attribute__((unused)) static inline _Bool config_ring_buffer_empty
( const struct config_ring_buffer *rb) { return rb->write ==
rb->read; } __attribute__((unused)) static inline void config_ring_buffer_init
( struct config_ring_buffer *rb) { rb->write = rb->read
= 0; } __attribute__((unused)) static inline void config_ring_buffer_put
( struct config_ring_buffer *rb, const struct config_line *e)
{ ((void) sizeof ((!config_ring_buffer_full(rb)) ? 1 : 0), __extension__
({ if (!config_ring_buffer_full(rb)) ; else __assert_fail ("!config_ring_buffer_full(rb)"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 85, __extension__ __PRETTY_FUNCTION__); })); memcpy(&rb
->array[config_ring_buffer_mask(rb->write++)], e, sizeof
(*e)); } __attribute__((unused)) static inline _Bool config_ring_buffer_try_put
( struct config_ring_buffer *rb, const struct config_line *e)
{ if (config_ring_buffer_full(rb)) return 0; memcpy(&rb->
array[config_ring_buffer_mask(rb->write++)], e, sizeof(*e)
); return 1; } __attribute__((unused)) static inline struct config_line
config_ring_buffer_get( struct config_ring_buffer *rb) { ((void
) sizeof ((!config_ring_buffer_empty(rb)) ? 1 : 0), __extension__
({ if (!config_ring_buffer_empty(rb)) ; else __assert_fail (
"!config_ring_buffer_empty(rb)", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 85, __extension__ __PRETTY_FUNCTION__); })); return rb->
array[config_ring_buffer_mask(rb->read++)]; } __attribute__
((unused)) static inline struct config_line *config_ring_buffer_get_ptr
( struct config_ring_buffer *rb) { ((void) sizeof ((!config_ring_buffer_empty
(rb)) ? 1 : 0), __extension__ ({ if (!config_ring_buffer_empty
(rb)) ; else __assert_fail ("!config_ring_buffer_empty(rb)", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 85, __extension__ __PRETTY_FUNCTION__); })); return &rb
->array[config_ring_buffer_mask(rb->read++)]; } __attribute__
((unused)) static inline struct config_line *config_ring_buffer_get_ptr_or_null
(struct config_ring_buffer *rb) { return config_ring_buffer_empty
(rb) ? ((void*)0) : &rb->array[config_ring_buffer_mask
(rb->read++)]; }
86
87struct lexer {
88 void *(*state)(struct lexer *);
89 const char *start, *pos, *end;
90 struct lexeme_ring_buffer buffer;
91 int cur_line;
92};
93
94struct parser {
95 void *(*state)(struct parser *);
96 struct lexer lexer;
97 struct lexeme_ring_buffer buffer;
98 struct config_ring_buffer items;
99 struct lwan_strbuf strbuf;
100};
101
102struct config {
103 struct parser parser;
104 char *error_message;
105 struct hash *constants;
106 struct {
107 void *addr;
108 size_t sz;
109 } mapped;
110 int opened_brackets;
111};
112
113unsigned int parse_time_period(const char *str, unsigned int default_value)
114{
115 unsigned int total = 0;
116 unsigned int period;
117 int ignored_spaces = 0;
118 char multiplier;
119
120 if (!str)
121 return default_value;
122
123 while (*str) {
124 /* This check is necessary to avoid making sscanf() take an incredible
125 * amount of time while trying to scan the input for a number. Fix for
126 * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=44910 */
127 if (isspace(*str)((*__ctype_b_loc ())[(int) ((*str))] & (unsigned short int
) _ISspace)
) {
128 ignored_spaces++;
129 str++;
130
131 if (ignored_spaces > 1024)
132 return default_value;
133
134 continue;
135 }
136
137 if (sscanf(str, "%u%c", &period, &multiplier) != 2)
138 break;
139
140 switch (multiplier) {
141 case 's': total += period; break;
142 case 'm': total += period * ONE_MINUTE60; break;
143 case 'h': total += period * ONE_HOUR(60 * 60); break;
144 case 'd': total += period * ONE_DAY((60 * 60) * 24); break;
145 case 'w': total += period * ONE_WEEK(((60 * 60) * 24) * 7); break;
146 case 'M': total += period * ONE_MONTH(((60 * 60) * 24) * 31); break;
147 case 'y': total += period * ONE_YEAR((((60 * 60) * 24) * 31) * 12); break;
148 default:
149 lwan_status_warning("Ignoring unknown multiplier: %c",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 150, __FUNCTION__, "Ignoring unknown multiplier: %c", multiplier
)
150 multiplier)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 150, __FUNCTION__, "Ignoring unknown multiplier: %c", multiplier
)
;
151 }
152
153 str = strchr(str, multiplier) + 1;
154 }
155
156 return total ? total : default_value;
157}
158
159long long parse_long_long(const char *value, long long default_value)
160{
161 char *endptr;
162 long long parsed;
163
164 if (!value)
165 return default_value;
166
167 errno(*__errno_location ()) = 0;
168 parsed = strtoll(value, &endptr, 0);
169
170 if (errno(*__errno_location ()) != 0)
171 return default_value;
172
173 if (*endptr != '\0' || value == endptr)
174 return default_value;
175
176 return parsed;
177}
178
179long parse_long(const char *value, long default_value)
180{
181 long long long_long_value = parse_long_long(value, default_value);
182
183 if ((long long)(long)long_long_value != long_long_value)
184 return default_value;
185
186 return (long)long_long_value;
187}
188
189int parse_int(const char *value, int default_value)
190{
191 long long_value = parse_long(value, default_value);
192
193 if ((long)(int)long_value != long_value)
194 return default_value;
195
196 return (int)long_value;
197}
198
199bool_Bool parse_bool(const char *value, bool_Bool default_value)
200{
201 if (!value)
202 return default_value;
203
204 if (strcaseequal_neutral(value, "true") ||
205 strcaseequal_neutral(value, "on") || strcaseequal_neutral(value, "yes"))
206 return true1;
207
208 if (strcaseequal_neutral(value, "false") ||
209 strcaseequal_neutral(value, "off") || strcaseequal_neutral(value, "no"))
210 return false0;
211
212 return parse_int(value, default_value);
213}
214
215LWAN_SELF_TEST(parse_bool)__attribute__((constructor)) static void self_test_parse_bool
(void)
216{
217 assert(parse_bool("true", false) == true)((void) sizeof ((parse_bool("true", 0) == 1) ? 1 : 0), __extension__
({ if (parse_bool("true", 0) == 1) ; else __assert_fail ("parse_bool(\"true\", false) == true"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 217, __extension__ __PRETTY_FUNCTION__); }))
;
218 assert(parse_bool("on", false) == true)((void) sizeof ((parse_bool("on", 0) == 1) ? 1 : 0), __extension__
({ if (parse_bool("on", 0) == 1) ; else __assert_fail ("parse_bool(\"on\", false) == true"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 218, __extension__ __PRETTY_FUNCTION__); }))
;
219 assert(parse_bool("yes", false) == true)((void) sizeof ((parse_bool("yes", 0) == 1) ? 1 : 0), __extension__
({ if (parse_bool("yes", 0) == 1) ; else __assert_fail ("parse_bool(\"yes\", false) == true"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 219, __extension__ __PRETTY_FUNCTION__); }))
;
220
221 assert(parse_bool("false", true) == false)((void) sizeof ((parse_bool("false", 1) == 0) ? 1 : 0), __extension__
({ if (parse_bool("false", 1) == 0) ; else __assert_fail ("parse_bool(\"false\", true) == false"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 221, __extension__ __PRETTY_FUNCTION__); }))
;
222 assert(parse_bool("off", true) == false)((void) sizeof ((parse_bool("off", 1) == 0) ? 1 : 0), __extension__
({ if (parse_bool("off", 1) == 0) ; else __assert_fail ("parse_bool(\"off\", true) == false"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 222, __extension__ __PRETTY_FUNCTION__); }))
;
223 assert(parse_bool("no", true) == false)((void) sizeof ((parse_bool("no", 1) == 0) ? 1 : 0), __extension__
({ if (parse_bool("no", 1) == 0) ; else __assert_fail ("parse_bool(\"no\", true) == false"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 223, __extension__ __PRETTY_FUNCTION__); }))
;
224
225 assert(parse_bool("0", 1) == false)((void) sizeof ((parse_bool("0", 1) == 0) ? 1 : 0), __extension__
({ if (parse_bool("0", 1) == 0) ; else __assert_fail ("parse_bool(\"0\", 1) == false"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 225, __extension__ __PRETTY_FUNCTION__); }))
;
226 assert(parse_bool("1", 0) == true)((void) sizeof ((parse_bool("1", 0) == 1) ? 1 : 0), __extension__
({ if (parse_bool("1", 0) == 1) ; else __assert_fail ("parse_bool(\"1\", 0) == true"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 226, __extension__ __PRETTY_FUNCTION__); }))
;
227
228 assert(parse_bool("abacate", true) == true)((void) sizeof ((parse_bool("abacate", 1) == 1) ? 1 : 0), __extension__
({ if (parse_bool("abacate", 1) == 1) ; else __assert_fail (
"parse_bool(\"abacate\", true) == true", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 228, __extension__ __PRETTY_FUNCTION__); }))
;
229 assert(parse_bool("abacate", false) == false)((void) sizeof ((parse_bool("abacate", 0) == 0) ? 1 : 0), __extension__
({ if (parse_bool("abacate", 0) == 0) ; else __assert_fail (
"parse_bool(\"abacate\", false) == false", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 229, __extension__ __PRETTY_FUNCTION__); }))
;
230}
231
232bool_Bool config_error(struct config *conf, const char *fmt, ...)
233{
234 va_list values;
235 int len;
236 char *output;
237
238 if (conf->error_message)
239 return false0;
240
241 va_start(values, fmt)__builtin_va_start(values, fmt);
242 len = vasprintf(&output, fmt, values);
243 va_end(values)__builtin_va_end(values);
244
245 if (len >= 0) {
246 conf->error_message = output;
247 return true1;
248 }
249
250 conf->error_message = NULL((void*)0);
251 return false0;
252}
253
254static void emit_lexeme(struct lexer *lexer, struct lexeme *lexeme)
255{
256 if (lexeme_ring_buffer_try_put(&lexer->buffer, lexeme))
257 lexer->start = lexer->pos;
258}
259
260static size_t current_len(struct lexer *lexer)
261{
262 return (size_t)(lexer->pos - lexer->start);
263}
264
265static void emit(struct lexer *lexer, enum lexeme_type type)
266{
267 struct lexeme lexeme = {
268 .type = type,
269 .value = {.value = lexer->start, .len = current_len(lexer)},
270 };
271 emit_lexeme(lexer, &lexeme);
272}
273
274static int next(struct lexer *lexer)
275{
276 if (lexer->pos >= lexer->end) {
277 lexer->pos = lexer->end + 1;
278 return '\0';
279 }
280
281 int r = *lexer->pos;
282 lexer->pos++;
283
284 if (r == '\n')
285 lexer->cur_line++;
286
287 return r;
288}
289
290static void ignore(struct lexer *lexer)
291{
292 lexer->start = lexer->pos;
293}
294
295static void advance_n(struct lexer *lexer, size_t n)
296{
297 lexer->pos += n;
298 ignore(lexer);
299}
300
301static void backup(struct lexer *lexer)
302{
303 lexer->pos--;
304
305 if (*lexer->pos == '\n')
306 lexer->cur_line--;
307}
308
309static int peek(struct lexer *lexer)
310{
311 int chr = next(lexer);
312
313 backup(lexer);
314
315 return chr;
316}
317
318static size_t remaining(struct lexer *lexer)
319{
320 return (size_t)(lexer->end - lexer->pos);
321}
322
323static void *lex_config(struct lexer *lexer);
324static void *lex_variable(struct lexer *lexer);
325
326static bool_Bool is_string(int chr)
327{
328 return chr && !isspace(chr)((*__ctype_b_loc ())[(int) ((chr))] & (unsigned short int
) _ISspace)
&& chr != '=' && chr != '#' && chr != '{' && chr != '}';
329}
330
331static void *lex_string(struct lexer *lexer)
332{
333 int chr;
334
335 do {
336 chr = next(lexer);
337
338 if (chr == '$' && peek(lexer) == '{') {
339 backup(lexer);
340 emit(lexer, LEXEME_STRING);
341
342 advance_n(lexer, strlen("{"));
343
344 return lex_variable;
345 }
346 } while (is_string(chr));
347
348 backup(lexer);
349 emit(lexer, LEXEME_STRING);
350
351 return lex_config;
352}
353
354static struct config *config_from_parser(struct parser *parser)
355{
356 return container_of(parser, struct config, parser)((struct config *) ((char *)(parser) - __builtin_offsetof(struct
config, parser)) + ((typeof(*(parser)) *)0 != (typeof(((struct
config *)0)->parser) *)0))
;
357}
358
359static struct config *config_from_lexer(struct lexer *lexer)
360{
361 struct parser *parser = container_of(lexer, struct parser, lexer)((struct parser *) ((char *)(lexer) - __builtin_offsetof(struct
parser, lexer)) + ((typeof(*(lexer)) *)0 != (typeof(((struct
parser *)0)->lexer) *)0))
;
362
363 return config_from_parser(parser);
364}
365
366static bool_Bool lex_streq(struct lexer *lexer, const char *str, size_t s)
367{
368 if (remaining(lexer) < s)
369 return false0;
370
371 return !strncmp(lexer->pos, str, s);
372}
373
374static void *lex_multiline_string(struct lexer *lexer)
375{
376 const char *end = (peek(lexer) == '"') ? "\"\"\"" : "'''";
377
378 advance_n(lexer, strlen("'''") - 1);
379
380 do {
381 if (lex_streq(lexer, end, 3)) {
382 emit(lexer, LEXEME_STRING);
383 lexer->pos += 3;
384
385 return lex_config;
386 }
387 } while (next(lexer) != '\0');
388
389 return LEX_ERROR(lexer, "EOF while scanning multiline string")({ config_error(config_from_lexer(lexer), "%s" "EOF while scanning multiline string"
, "Syntax error: "); ((void*)0); })
;
390}
391
392static bool_Bool is_variable(int chr)
393{
394 return isalpha(chr)((*__ctype_b_loc ())[(int) ((chr))] & (unsigned short int
) _ISalpha)
|| chr == '_';
395}
396
397static void *lex_variable_default(struct lexer *lexer)
398{
399 int chr;
400
401 do {
402 chr = next(lexer);
403
404 if (chr == '}') {
405 backup(lexer);
406 emit(lexer, LEXEME_STRING);
407
408 advance_n(lexer, strlen("}"));
409
410 return lex_config;
411 }
412 } while (chr != '\0');
413
414 return LEX_ERROR(lexer, "EOF while scanning for default value for variable")({ config_error(config_from_lexer(lexer), "%s" "EOF while scanning for default value for variable"
, "Syntax error: "); ((void*)0); })
;
415}
416
417static void *lex_variable(struct lexer *lexer)
418{
419 int chr;
420
421 advance_n(lexer, strlen("${") - 1);
422
423 do {
424 chr = next(lexer);
425
426 if (chr == ':') {
427 backup(lexer);
428
429 if (!current_len(lexer))
430 return LEX_ERROR(lexer, "Expecting environment variable name")({ config_error(config_from_lexer(lexer), "%s" "Expecting environment variable name"
, "Syntax error: "); ((void*)0); })
;
431
432 emit(lexer, LEXEME_VARIABLE_DEFAULT);
433 advance_n(lexer, strlen(":"));
434 return lex_variable_default;
435 }
436
437 if (chr == '}') {
438 backup(lexer);
439
440 if (!current_len(lexer))
441 return LEX_ERROR(lexer, "Expecting environment variable name")({ config_error(config_from_lexer(lexer), "%s" "Expecting environment variable name"
, "Syntax error: "); ((void*)0); })
;
442
443 emit(lexer, LEXEME_VARIABLE);
444 advance_n(lexer, strlen("}"));
445
446 return lex_config;
447 }
448 } while (is_variable(chr));
449
450 return LEX_ERROR(lexer, "EOF while scanning for end of variable")({ config_error(config_from_lexer(lexer), "%s" "EOF while scanning for end of variable"
, "Syntax error: "); ((void*)0); })
;
451}
452
453static bool_Bool is_comment(int chr)
454{
455 return chr != '\0' && chr != '\n';
456}
457
458static void *lex_comment(struct lexer *lexer)
459{
460 while (is_comment(next(lexer)))
461 ;
462 backup(lexer);
463 return lex_config;
464}
465
466static void *lex_config(struct lexer *lexer)
467{
468 while (true1) {
469 int chr = next(lexer);
470
471 if (chr == '\0')
472 break;
473
474 if (chr == '\n') {
475 emit(lexer, LEXEME_LINEFEED);
476 return lex_config;
477 }
478
479 if (isspace(chr)((*__ctype_b_loc ())[(int) ((chr))] & (unsigned short int
) _ISspace)
) {
480 ignore(lexer);
481 continue;
482 }
483
484 if (chr == '{') {
485 emit(lexer, LEXEME_OPEN_BRACKET);
486 return lex_config;
487 }
488
489 if (chr == '}') {
490 /* Emitting a linefeed lexeme before a close bracket lexeme
491 * simplifies the parser and allows for situations where a
492 * section is closed when declaring a key/value pair
493 * (e.g. "section{key=value}" all in a single line).
494 */
495 emit(lexer, LEXEME_LINEFEED);
496 emit(lexer, LEXEME_CLOSE_BRACKET);
497 return lex_config;
498 }
499
500 if (chr == '=') {
501 emit(lexer, LEXEME_EQUAL);
502 return lex_config;
503 }
504
505 if (chr == '#')
506 return lex_comment;
507
508 if (chr == '\'' && lex_streq(lexer, "''", 2))
509 return lex_multiline_string;
510 if (chr == '"' && lex_streq(lexer, "\"\"", 2))
511 return lex_multiline_string;
512
513 if (chr == '$' && peek(lexer) == '{')
514 return lex_variable;
515
516 if (is_string(chr))
517 return lex_string;
518
519 return LEX_ERROR(lexer, "Invalid character: '%c'", chr)({ config_error(config_from_lexer(lexer), "%s" "Invalid character: '%c'"
, "Syntax error: ", chr); ((void*)0); })
;
520 }
521
522 emit(lexer, LEXEME_LINEFEED);
523 emit(lexer, LEXEME_EOF);
524
525 return NULL((void*)0);
526}
527
528static const struct lexeme *lex_next(struct lexer *lexer)
529{
530 while (lexer->state) {
531 const struct lexeme *lexeme;
532
533 if ((lexeme = lexeme_ring_buffer_get_ptr_or_null(&lexer->buffer)))
534 return lexeme;
535
536 lexer->state = lexer->state(lexer);
537 }
538
539 return lexeme_ring_buffer_get_ptr_or_null(&lexer->buffer);
540}
541
542static void *parse_config(struct parser *parser);
543static void *parse_section_end(struct parser *parser);
544
545#define ENV_VAR_NAME_LEN_MAX64 64
546
547static __attribute__((noinline)) const char *
548get_constant(struct parser *parser, const char *key, size_t len)
549{
550 if (UNLIKELY(len > ENV_VAR_NAME_LEN_MAX)__builtin_expect(((len > 64)), (0))) {
551 return PARSER_ERROR(parser, "Variable name \"%.*s\" exceeds %d bytes",({ config_error(config_from_parser(parser), "%s" "Variable name \"%.*s\" exceeds %d bytes"
, "Parsing error: ", (int)len, key, 64); ((void*)0); })
552 (int)len, key, ENV_VAR_NAME_LEN_MAX)({ config_error(config_from_parser(parser), "%s" "Variable name \"%.*s\" exceeds %d bytes"
, "Parsing error: ", (int)len, key, 64); ((void*)0); })
;
553 }
554
555 const char *key_copy = strndupa(key, len)(__extension__ ({ const char *__old = (key); size_t __len = strnlen
(__old, (len)); char *__new = (char *) __builtin_alloca (__len
+ 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len
); }))
;
556 const char *value =
557 hash_find(config_from_parser(parser)->constants, key_copy);
558 return value ? value : secure_getenv(key_copy);
559}
560
561static void *parse_key_value(struct parser *parser)
562{
563 struct config_line line = {.type = CONFIG_LINE_TYPE_LINE};
564 const struct lexeme *lexeme;
565 enum lexeme_type last_lexeme = TOTAL_LEXEMES;
566 size_t key_size;
567
568 while ((lexeme = lexeme_ring_buffer_get_ptr_or_null(&parser->buffer))) {
569 if (lexeme->type != LEXEME_STRING)
570 return PARSER_ERROR(parser, "Expecting string")({ config_error(config_from_parser(parser), "%s" "Expecting string"
, "Parsing error: "); ((void*)0); })
;
571
572 lwan_strbuf_append_str(&parser->strbuf, lexeme->value.value,
573 lexeme->value.len);
574
575 if (!lexeme_ring_buffer_empty(&parser->buffer))
576 lwan_strbuf_append_char(&parser->strbuf, '_');
577 }
578 key_size = lwan_strbuf_get_length(&parser->strbuf);
579 lwan_strbuf_append_char(&parser->strbuf, '\0');
580
581 while ((lexeme = lex_next(&parser->lexer))) {
582 if (UNLIKELY(lwan_strbuf_get_length(&parser->strbuf) > 1ull<<20)__builtin_expect(((lwan_strbuf_get_length(&parser->strbuf
) > 1ull<<20)), (0))
) {
583 /* 1MiB is more than sufficient for a value. (Without this validation
584 * here, fuzzers often generates values that are gigabite sized.) */
585 return PARSER_ERROR(parser, "Value too long")({ config_error(config_from_parser(parser), "%s" "Value too long"
, "Parsing error: "); ((void*)0); })
;
586 }
587
588 switch (lexeme->type) {
589 case LEXEME_VARIABLE: {
590 const char *value =
591 get_constant(parser, lexeme->value.value, lexeme->value.len);
592 if (!value) {
593 return PARSER_ERROR(({ config_error(config_from_parser(parser), "%s" "Variable '$%.*s' not defined in a constants section "
"or as an environment variable", "Parsing error: ", (int)lexeme
->value.len, lexeme->value.value); ((void*)0); })
594 parser,({ config_error(config_from_parser(parser), "%s" "Variable '$%.*s' not defined in a constants section "
"or as an environment variable", "Parsing error: ", (int)lexeme
->value.len, lexeme->value.value); ((void*)0); })
595 "Variable '$%.*s' not defined in a constants section "({ config_error(config_from_parser(parser), "%s" "Variable '$%.*s' not defined in a constants section "
"or as an environment variable", "Parsing error: ", (int)lexeme
->value.len, lexeme->value.value); ((void*)0); })
596 "or as an environment variable",({ config_error(config_from_parser(parser), "%s" "Variable '$%.*s' not defined in a constants section "
"or as an environment variable", "Parsing error: ", (int)lexeme
->value.len, lexeme->value.value); ((void*)0); })
597 (int)lexeme->value.len, lexeme->value.value)({ config_error(config_from_parser(parser), "%s" "Variable '$%.*s' not defined in a constants section "
"or as an environment variable", "Parsing error: ", (int)lexeme
->value.len, lexeme->value.value); ((void*)0); })
;
598 }
599
600 lwan_strbuf_append_strz(&parser->strbuf, value);
601
602 break;
603 }
604
605 case LEXEME_VARIABLE_DEFAULT: {
606 const char *value =
607 get_constant(parser, lexeme->value.value, lexeme->value.len);
608 const struct lexeme *var_name = lexeme;
609
610 if (!(lexeme = lex_next(&parser->lexer))) {
611 return PARSER_ERROR(({ config_error(config_from_parser(parser), "%s" "Default value for constant '$%.*s' not given"
, "Parsing error: ", (int)var_name->value.len, var_name->
value.value); ((void*)0); })
612 parser, "Default value for constant '$%.*s' not given",({ config_error(config_from_parser(parser), "%s" "Default value for constant '$%.*s' not given"
, "Parsing error: ", (int)var_name->value.len, var_name->
value.value); ((void*)0); })
613 (int)var_name->value.len, var_name->value.value)({ config_error(config_from_parser(parser), "%s" "Default value for constant '$%.*s' not given"
, "Parsing error: ", (int)var_name->value.len, var_name->
value.value); ((void*)0); })
;
614 }
615
616 if (lexeme->type != LEXEME_STRING)
617 return PARSER_ERROR(parser, "Wrong format for default value")({ config_error(config_from_parser(parser), "%s" "Wrong format for default value"
, "Parsing error: "); ((void*)0); })
;
618
619 if (!value) {
620 lwan_status_debug(lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 623, __FUNCTION__, "Using default value of '%.*s' for variable '${%.*s}'"
, (int)lexeme->value.len, lexeme->value.value, (int)var_name
->value.len, var_name->value.value)
621 "Using default value of '%.*s' for variable '${%.*s}'",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 623, __FUNCTION__, "Using default value of '%.*s' for variable '${%.*s}'"
, (int)lexeme->value.len, lexeme->value.value, (int)var_name
->value.len, var_name->value.value)
622 (int)lexeme->value.len, lexeme->value.value,lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 623, __FUNCTION__, "Using default value of '%.*s' for variable '${%.*s}'"
, (int)lexeme->value.len, lexeme->value.value, (int)var_name
->value.len, var_name->value.value)
623 (int)var_name->value.len, var_name->value.value)lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 623, __FUNCTION__, "Using default value of '%.*s' for variable '${%.*s}'"
, (int)lexeme->value.len, lexeme->value.value, (int)var_name
->value.len, var_name->value.value)
;
624 lwan_strbuf_append_str(&parser->strbuf, lexeme->value.value,
625 lexeme->value.len);
626 } else {
627 lwan_strbuf_append_strz(&parser->strbuf, value);
628 }
629
630 break;
631 }
632
633 case LEXEME_EQUAL:
634 lwan_strbuf_append_char(&parser->strbuf, '=');
635 break;
636
637 case LEXEME_STRING:
638 if (last_lexeme == LEXEME_STRING)
639 lwan_strbuf_append_char(&parser->strbuf, ' ');
640
641 lwan_strbuf_append_str(&parser->strbuf, lexeme->value.value,
642 lexeme->value.len);
643
644 break;
645
646 case LEXEME_LINEFEED:
647 line.key = lwan_strbuf_get_buffer(&parser->strbuf);
648 line.value = line.key + key_size + 1;
649
650 if (config_ring_buffer_try_put(&parser->items, &line))
651 return parse_config;
652
653 return PARSER_ERROR(parser,({ config_error(config_from_parser(parser), "%s" "Could not add key/value to ring buffer"
, "Parsing error: "); ((void*)0); })
654 "Could not add key/value to ring buffer")({ config_error(config_from_parser(parser), "%s" "Could not add key/value to ring buffer"
, "Parsing error: "); ((void*)0); })
;
655
656 case LEXEME_OPEN_BRACKET:
657 return PARSER_ERROR(parser, "Open bracket not expected here")({ config_error(config_from_parser(parser), "%s" "Open bracket not expected here"
, "Parsing error: "); ((void*)0); })
;
658
659 case LEXEME_CLOSE_BRACKET:
660 return INTERNAL_ERROR(({ config_error(config_from_parser(parser), "%s" "Close bracket found while parsing key/value"
, "Internal error: "); ((void*)0); })
661 parser, "Close bracket found while parsing key/value")({ config_error(config_from_parser(parser), "%s" "Close bracket found while parsing key/value"
, "Internal error: "); ((void*)0); })
;
662
663 case LEXEME_EOF:
664 return INTERNAL_ERROR(({ config_error(config_from_parser(parser), "%s" "EOF found while parsing key/value"
, "Internal error: "); ((void*)0); })
665 parser, "EOF found while parsing key/value")({ config_error(config_from_parser(parser), "%s" "EOF found while parsing key/value"
, "Internal error: "); ((void*)0); })
;
666
667 case TOTAL_LEXEMES:
668 __builtin_unreachable();
669 }
670
671 last_lexeme = lexeme->type;
672 }
673
674 return PARSER_ERROR(parser, "EOF while parsing key-value")({ config_error(config_from_parser(parser), "%s" "EOF while parsing key-value"
, "Parsing error: "); ((void*)0); })
;
675}
676
677static void *parse_section(struct parser *parser)
678{
679 const struct lexeme *lexeme;
680 size_t name_len;
681
682 lexeme = lexeme_ring_buffer_get_ptr_or_null(&parser->buffer);
683 if (!lexeme || lexeme->type != LEXEME_STRING)
684 return PARSER_ERROR(parser, "Expecting a string")({ config_error(config_from_parser(parser), "%s" "Expecting a string"
, "Parsing error: "); ((void*)0); })
;
685
686 lwan_strbuf_append_str(&parser->strbuf, lexeme->value.value,
687 lexeme->value.len);
688 name_len = lexeme->value.len;
689 lwan_strbuf_append_char(&parser->strbuf, '\0');
690
691 while ((lexeme = lexeme_ring_buffer_get_ptr_or_null(&parser->buffer))) {
692 if (lexeme->type != LEXEME_STRING)
693 return PARSER_ERROR(parser, "Expecting a string")({ config_error(config_from_parser(parser), "%s" "Expecting a string"
, "Parsing error: "); ((void*)0); })
;
694
695 lwan_strbuf_append_str(&parser->strbuf, lexeme->value.value,
696 lexeme->value.len);
697
698 if (!lexeme_ring_buffer_empty(&parser->buffer))
699 lwan_strbuf_append_char(&parser->strbuf, ' ');
700 }
701
702 struct config_line line = {
703 .type = CONFIG_LINE_TYPE_SECTION,
704 .key = lwan_strbuf_get_buffer(&parser->strbuf),
705 .value = lwan_strbuf_get_buffer(&parser->strbuf) + name_len + 1,
706 };
707 return config_ring_buffer_try_put(&parser->items, &line) ? parse_config
708 : NULL((void*)0);
709}
710
711static void *parse_section_shorthand(struct parser *parser)
712{
713 void *next_state = parse_section(parser);
714
715 if (next_state) {
716 struct config_line line = {.type = CONFIG_LINE_TYPE_SECTION_END};
717
718 if (config_ring_buffer_try_put(&parser->items, &line))
719 return next_state;
720
721 return INTERNAL_ERROR(parser, "couldn't append line to internal ring buffer")({ config_error(config_from_parser(parser), "%s" "couldn't append line to internal ring buffer"
, "Internal error: "); ((void*)0); })
;
722 }
723
724 return NULL((void*)0);
725}
726
727static void *parse_section_end(struct parser *parser)
728{
729 struct config_line line = {.type = CONFIG_LINE_TYPE_SECTION_END};
730 struct config *config = config_from_parser(parser);
731
732 if (!config->opened_brackets)
733 return PARSER_ERROR(parser, "Section closed before it opened")({ config_error(config_from_parser(parser), "%s" "Section closed before it opened"
, "Parsing error: "); ((void*)0); })
;
734
735 if (!lexeme_ring_buffer_empty(&parser->buffer))
736 return PARSER_ERROR(parser, "Not expecting a close bracket here")({ config_error(config_from_parser(parser), "%s" "Not expecting a close bracket here"
, "Parsing error: "); ((void*)0); })
;
737
738 if (!config_ring_buffer_try_put(&parser->items, &line)) {
739 return INTERNAL_ERROR(parser,({ config_error(config_from_parser(parser), "%s" "could not store section end in ring buffer"
, "Internal error: "); ((void*)0); })
740 "could not store section end in ring buffer")({ config_error(config_from_parser(parser), "%s" "could not store section end in ring buffer"
, "Internal error: "); ((void*)0); })
;
741 }
742
743 config->opened_brackets--;
744
745 return parse_config;
746}
747
748static void *parse_config(struct parser *parser)
749{
750 const struct lexeme *lexeme = lex_next(&parser->lexer);
751
752 if (!lexeme) {
753 /* EOF is signaled by a LEXEME_EOF from the parser, so
754 * this should never happen. */
755 return INTERNAL_ERROR(parser, "could not obtain lexeme")({ config_error(config_from_parser(parser), "%s" "could not obtain lexeme"
, "Internal error: "); ((void*)0); })
;
756 }
757
758 switch (lexeme->type) {
759 case LEXEME_EQUAL:
760 if (lexeme_ring_buffer_empty(&parser->buffer))
761 return PARSER_ERROR(parser, "Keys can´t be empty")({ config_error(config_from_parser(parser), "%s" "Keys can´t be empty"
, "Parsing error: "); ((void*)0); })
;
762
763 return parse_key_value;
764
765 case LEXEME_OPEN_BRACKET:
766 if (lexeme_ring_buffer_empty(&parser->buffer))
767 return PARSER_ERROR(parser, "Section names can´t be empty")({ config_error(config_from_parser(parser), "%s" "Section names can´t be empty"
, "Parsing error: "); ((void*)0); })
;
768
769 config_from_parser(parser)->opened_brackets++;
770
771 return parse_section;
772
773 case LEXEME_LINEFEED:
774 if (!lexeme_ring_buffer_empty(&parser->buffer))
775 return parse_section_shorthand;
776
777 return parse_config;
778
779 case LEXEME_STRING:
780 if (!lexeme_ring_buffer_try_put(&parser->buffer, lexeme))
781 return INTERNAL_ERROR(parser, "could not store string in ring buffer")({ config_error(config_from_parser(parser), "%s" "could not store string in ring buffer"
, "Internal error: "); ((void*)0); })
;
782
783 return parse_config;
784
785 case LEXEME_CLOSE_BRACKET:
786 return parse_section_end;
787
788 case LEXEME_EOF:
789 if (config_from_parser(parser)->opened_brackets)
790 return PARSER_ERROR(parser, "EOF while looking for a close bracket")({ config_error(config_from_parser(parser), "%s" "EOF while looking for a close bracket"
, "Parsing error: "); ((void*)0); })
;
791
792 if (!lexeme_ring_buffer_empty(&parser->buffer))
793 return INTERNAL_ERROR(parser, "premature EOF")({ config_error(config_from_parser(parser), "%s" "premature EOF"
, "Internal error: "); ((void*)0); })
;
794
795 break;
796
797 case LEXEME_VARIABLE:
798 case LEXEME_VARIABLE_DEFAULT:
799 return PARSER_ERROR(parser, "Variable '%.*s' can't be used here",({ config_error(config_from_parser(parser), "%s" "Variable '%.*s' can't be used here"
, "Parsing error: ", (int)lexeme->value.len, lexeme->value
.value); ((void*)0); })
800 (int)lexeme->value.len, lexeme->value.value)({ config_error(config_from_parser(parser), "%s" "Variable '%.*s' can't be used here"
, "Parsing error: ", (int)lexeme->value.len, lexeme->value
.value); ((void*)0); })
;
801
802 case TOTAL_LEXEMES:
803 __builtin_unreachable();
804 }
805
806 return NULL((void*)0);
807}
808
809static const struct config_line *parser_next_internal(struct parser *parser)
810{
811 while (parser->state) {
812 const struct config_line *line;
813
814 if ((line = config_ring_buffer_get_ptr_or_null(&parser->items)))
815 return line;
816
817 lwan_strbuf_reset(&parser->strbuf);
818
819 parser->state = parser->state(parser);
820 }
821
822 return config_ring_buffer_get_ptr_or_null(&parser->items);
823}
824
825static bool_Bool parse_constants(struct config *config, const struct config_line *l)
826{
827 while ((l = config_read_line(config))) {
12
Loop condition is true. Entering loop body
18
Execution continues on line 827
19
Potential leak of memory pointed to by 'v'
828 switch (l->type) {
13
Control jumps to 'case CONFIG_LINE_TYPE_LINE:' at line 829
829 case CONFIG_LINE_TYPE_LINE: {
830 char *k = strdup(l->key);
831 char *v = strdup(l->value);
14
Memory is allocated
832
833 if (!k || !v)
15
Assuming 'k' is non-null
16
Assuming 'v' is non-null
17
Taking false branch
834 lwan_status_critical("Can't allocate memory for constant")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 834, __FUNCTION__, "Can't allocate memory for constant")
;
835
836 hash_add(config->constants, k, v);
837 break;
838 }
839
840 case CONFIG_LINE_TYPE_SECTION_END:
841 return true1;
842
843 case CONFIG_LINE_TYPE_SECTION:
844 config_error(config, "Constants section can't be nested");
845 return false0;
846 }
847 }
848
849 return true1;
850}
851
852static const struct config_line *parser_next(struct parser *parser)
853{
854 while (true1) {
7
Loop condition is true. Entering loop body
855 const struct config_line *l = parser_next_internal(parser);
856
857 if (!l
7.1
'l' is non-null
)
858 return NULL((void*)0);
859
860 if (l->type == CONFIG_LINE_TYPE_SECTION && streq(l->key, "constants") &&
8
Assuming field 'type' is equal to CONFIG_LINE_TYPE_SECTION
10
Taking true branch
861 config_from_parser(parser)->opened_brackets == 1) {
9
Assuming field 'opened_brackets' is equal to 1
862 struct config *config = config_from_parser(parser);
863
864 if (parse_constants(config, l))
11
Calling 'parse_constants'
865 continue;
866
867 return PARSER_ERROR(parser, "Could not parse constants section: %s",({ config_error(config_from_parser(parser), "%s" "Could not parse constants section: %s"
, "Parsing error: ", config_last_error(config)); ((void*)0); }
)
868 config_last_error(config))({ config_error(config_from_parser(parser), "%s" "Could not parse constants section: %s"
, "Parsing error: ", config_last_error(config)); ((void*)0); }
)
;
869 }
870
871 return l;
872 }
873}
874
875static struct config *
876config_open_path(const char *path, void **data, size_t *size)
877{
878 struct config *config;
879 struct stat st;
880 void *mapped;
881 int fd;
882
883 fd = open(path, O_RDONLY00 | O_CLOEXEC02000000);
884 if (fd < 0) {
885 lwan_status_perror("Could not open configuration file: %s", path)lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 885, __FUNCTION__, "Could not open configuration file: %s",
path)
;
886 return NULL((void*)0);
887 }
888
889 if (fstat(fd, &st) < 0) {
890 close(fd);
891 return NULL((void*)0);
892 }
893
894 mapped = mmap(NULL((void*)0), (size_t)st.st_size, PROT_READ0x1, MAP_PRIVATE0x02, fd, 0);
895 close(fd);
896 if (mapped == MAP_FAILED((void *) -1))
897 return NULL((void*)0);
898
899 config = malloc(sizeof(*config));
900 if (!config) {
901 munmap(mapped, (size_t)st.st_size);
902 return NULL((void*)0);
903 }
904
905 *data = config->mapped.addr = mapped;
906 *size = config->mapped.sz = (size_t)st.st_size;
907
908 return config;
909}
910
911static struct config *
912config_init_data(struct config *config, const void *data, size_t len)
913{
914 config->parser = (struct parser){
915 .state = parse_config,
916 .lexer =
917 {
918 .state = lex_config,
919 .pos = data,
920 .start = data,
921 .end = (char *)data + len,
922 .cur_line = 1,
923 },
924 };
925
926 config->error_message = NULL((void*)0);
927 config->opened_brackets = 0;
928
929 config->constants = hash_str_new(free, free);
930
931 lwan_strbuf_init(&config->parser.strbuf);
932 config_ring_buffer_init(&config->parser.items);
933 lexeme_ring_buffer_init(&config->parser.buffer);
934
935 return config;
936}
937
938struct config *config_open(const char *path)
939{
940 struct config *config;
941 void *data;
942 size_t len;
943
944 config = config_open_path(path, &data, &len);
945 return config ? config_init_data(config, data, len) : NULL((void*)0);
946}
947
948#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
949struct config *config_open_for_fuzzing(const uint8_t *data, size_t len)
950{
951 struct config *config = malloc(sizeof(*config));
952
953 if (config) {
954 config->mapped.addr = NULL((void*)0);
955 config->mapped.sz = 0;
956
957 return config_init_data(config, data, len - 1);
958 }
959
960 return NULL((void*)0);
961}
962#endif
963
964void config_close(struct config *config)
965{
966 if (!config)
967 return;
968
969#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
970 if (config->mapped.addr)
971 munmap(config->mapped.addr, config->mapped.sz);
972#endif
973
974 hash_unref(config->constants);
975
976 free(config->error_message);
977 lwan_strbuf_free(&config->parser.strbuf);
978 free(config);
979}
980
981const struct config_line *config_read_line(struct config *conf)
982{
983 return conf->error_message ? NULL((void*)0) : parser_next(&conf->parser);
984}
985
986static bool_Bool find_section_end(struct config *config)
987{
988 const struct config_line *line;
989 int cur_level = 1;
990
991 if (config->error_message)
4
Assuming field 'error_message' is null
5
Taking false branch
992 return false0;
993
994 while ((line = parser_next(&config->parser))) {
6
Calling 'parser_next'
995 if (line->type == CONFIG_LINE_TYPE_SECTION) {
996 cur_level++;
997 } else if (line->type == CONFIG_LINE_TYPE_SECTION_END) {
998 cur_level--;
999
1000 if (!cur_level)
1001 return true1;
1002 }
1003 }
1004
1005 return false0;
1006}
1007
1008struct config *config_isolate_section(struct config *current_conf,
1009 const struct config_line *current_line)
1010{
1011 struct lexer *lexer;
1012 struct config *isolated;
1013 const char *pos;
1014
1015 if (current_line->type != CONFIG_LINE_TYPE_SECTION)
1016 return NULL((void*)0);
1017
1018 isolated = malloc(sizeof(*isolated));
1019 if (!isolated)
1020 return NULL((void*)0);
1021
1022 memcpy(isolated, current_conf, sizeof(*isolated));
1023 lwan_strbuf_init(&isolated->parser.strbuf);
1024
1025 isolated->constants = hash_ref(current_conf->constants);
1026
1027 isolated->mapped.addr = NULL((void*)0);
1028 isolated->mapped.sz = 0;
1029 /* Keep opened_brackets from the original */
1030
1031 lexer = &isolated->parser.lexer;
1032 lexer->start = lexer->pos;
1033
1034 pos = isolated->parser.lexer.pos;
1035 if (!find_section_end(isolated)) {
1036 config_error(current_conf,
1037 "Could not find section end while trying to isolate: %s",
1038 config_last_error(isolated));
1039
1040 hash_unref(isolated->constants);
1041 lwan_strbuf_free(&isolated->parser.strbuf);
1042 free(isolated);
1043
1044 return NULL((void*)0);
1045 }
1046
1047 lexer->end = lexer->pos;
1048 lexer->start = lexer->pos = pos;
1049
1050 return isolated;
1051}
1052
1053bool_Bool config_skip_section(struct config *conf, const struct config_line *line)
1054{
1055 if (line->type != CONFIG_LINE_TYPE_SECTION)
1
Assuming field 'type' is equal to CONFIG_LINE_TYPE_SECTION
2
Taking false branch
1056 return false0;
1057
1058 return find_section_end(conf);
3
Calling 'find_section_end'
1059}
1060
1061const char *config_last_error(struct config *conf)
1062{
1063 return conf->error_message;
1064}
1065
1066int config_cur_line(struct config *conf)
1067{
1068 return conf->parser.lexer.cur_line;
1069}