Bug Summary

File:lib/lwan-config.c
Warning:line 821, 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-18-040207-1926658-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 switch (lexeme->type) {
583 case LEXEME_VARIABLE: {
584 const char *value =
585 get_constant(parser, lexeme->value.value, lexeme->value.len);
586 if (!value) {
587 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); })
588 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); })
589 "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); })
590 "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); })
591 (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); })
;
592 }
593
594 lwan_strbuf_append_strz(&parser->strbuf, value);
595
596 break;
597 }
598
599 case LEXEME_VARIABLE_DEFAULT: {
600 const char *value =
601 get_constant(parser, lexeme->value.value, lexeme->value.len);
602 const struct lexeme *var_name = lexeme;
603
604 if (!(lexeme = lex_next(&parser->lexer))) {
605 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); })
606 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); })
607 (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); })
;
608 }
609
610 if (lexeme->type != LEXEME_STRING)
611 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); })
;
612
613 if (!value) {
614 lwan_status_debug(lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 617, __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)
615 "Using default value of '%.*s' for variable '${%.*s}'",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 617, __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)
616 (int)lexeme->value.len, lexeme->value.value,lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-config.c"
, 617, __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)
617 (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"
, 617, __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)
;
618 lwan_strbuf_append_str(&parser->strbuf, lexeme->value.value,
619 lexeme->value.len);
620 } else {
621 lwan_strbuf_append_strz(&parser->strbuf, value);
622 }
623
624 break;
625 }
626
627 case LEXEME_EQUAL:
628 lwan_strbuf_append_char(&parser->strbuf, '=');
629 break;
630
631 case LEXEME_STRING:
632 if (last_lexeme == LEXEME_STRING)
633 lwan_strbuf_append_char(&parser->strbuf, ' ');
634
635 lwan_strbuf_append_str(&parser->strbuf, lexeme->value.value,
636 lexeme->value.len);
637
638 break;
639
640 case LEXEME_LINEFEED:
641 line.key = lwan_strbuf_get_buffer(&parser->strbuf);
642 line.value = line.key + key_size + 1;
643
644 if (config_ring_buffer_try_put(&parser->items, &line))
645 return parse_config;
646
647 return PARSER_ERROR(parser,({ config_error(config_from_parser(parser), "%s" "Could not add key/value to ring buffer"
, "Parsing error: "); ((void*)0); })
648 "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); })
;
649
650 case LEXEME_OPEN_BRACKET:
651 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); })
;
652
653 case LEXEME_CLOSE_BRACKET:
654 return INTERNAL_ERROR(({ config_error(config_from_parser(parser), "%s" "Close bracket found while parsing key/value"
, "Internal error: "); ((void*)0); })
655 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); })
;
656
657 case LEXEME_EOF:
658 return INTERNAL_ERROR(({ config_error(config_from_parser(parser), "%s" "EOF found while parsing key/value"
, "Internal error: "); ((void*)0); })
659 parser, "EOF found while parsing key/value")({ config_error(config_from_parser(parser), "%s" "EOF found while parsing key/value"
, "Internal error: "); ((void*)0); })
;
660
661 case TOTAL_LEXEMES:
662 __builtin_unreachable();
663 }
664
665 last_lexeme = lexeme->type;
666 }
667
668 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); })
;
669}
670
671static void *parse_section(struct parser *parser)
672{
673 const struct lexeme *lexeme;
674 size_t name_len;
675
676 lexeme = lexeme_ring_buffer_get_ptr_or_null(&parser->buffer);
677 if (!lexeme || lexeme->type != LEXEME_STRING)
678 return PARSER_ERROR(parser, "Expecting a string")({ config_error(config_from_parser(parser), "%s" "Expecting a string"
, "Parsing error: "); ((void*)0); })
;
679
680 lwan_strbuf_append_str(&parser->strbuf, lexeme->value.value,
681 lexeme->value.len);
682 name_len = lexeme->value.len;
683 lwan_strbuf_append_char(&parser->strbuf, '\0');
684
685 while ((lexeme = lexeme_ring_buffer_get_ptr_or_null(&parser->buffer))) {
686 if (lexeme->type != LEXEME_STRING)
687 return PARSER_ERROR(parser, "Expecting a string")({ config_error(config_from_parser(parser), "%s" "Expecting a string"
, "Parsing error: "); ((void*)0); })
;
688
689 lwan_strbuf_append_str(&parser->strbuf, lexeme->value.value,
690 lexeme->value.len);
691
692 if (!lexeme_ring_buffer_empty(&parser->buffer))
693 lwan_strbuf_append_char(&parser->strbuf, ' ');
694 }
695
696 struct config_line line = {
697 .type = CONFIG_LINE_TYPE_SECTION,
698 .key = lwan_strbuf_get_buffer(&parser->strbuf),
699 .value = lwan_strbuf_get_buffer(&parser->strbuf) + name_len + 1,
700 };
701 return config_ring_buffer_try_put(&parser->items, &line) ? parse_config
702 : NULL((void*)0);
703}
704
705static void *parse_section_shorthand(struct parser *parser)
706{
707 void *next_state = parse_section(parser);
708
709 if (next_state) {
710 struct config_line line = {.type = CONFIG_LINE_TYPE_SECTION_END};
711
712 if (config_ring_buffer_try_put(&parser->items, &line))
713 return next_state;
714
715 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); })
;
716 }
717
718 return NULL((void*)0);
719}
720
721static void *parse_section_end(struct parser *parser)
722{
723 struct config_line line = {.type = CONFIG_LINE_TYPE_SECTION_END};
724 struct config *config = config_from_parser(parser);
725
726 if (!config->opened_brackets)
727 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); })
;
728
729 if (!lexeme_ring_buffer_empty(&parser->buffer))
730 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); })
;
731
732 if (!config_ring_buffer_try_put(&parser->items, &line)) {
733 return INTERNAL_ERROR(parser,({ config_error(config_from_parser(parser), "%s" "could not store section end in ring buffer"
, "Internal error: "); ((void*)0); })
734 "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); })
;
735 }
736
737 config->opened_brackets--;
738
739 return parse_config;
740}
741
742static void *parse_config(struct parser *parser)
743{
744 const struct lexeme *lexeme = lex_next(&parser->lexer);
745
746 if (!lexeme) {
747 /* EOF is signaled by a LEXEME_EOF from the parser, so
748 * this should never happen. */
749 return INTERNAL_ERROR(parser, "could not obtain lexeme")({ config_error(config_from_parser(parser), "%s" "could not obtain lexeme"
, "Internal error: "); ((void*)0); })
;
750 }
751
752 switch (lexeme->type) {
753 case LEXEME_EQUAL:
754 if (lexeme_ring_buffer_empty(&parser->buffer))
755 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); })
;
756
757 return parse_key_value;
758
759 case LEXEME_OPEN_BRACKET:
760 if (lexeme_ring_buffer_empty(&parser->buffer))
761 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); })
;
762
763 config_from_parser(parser)->opened_brackets++;
764
765 return parse_section;
766
767 case LEXEME_LINEFEED:
768 if (!lexeme_ring_buffer_empty(&parser->buffer))
769 return parse_section_shorthand;
770
771 return parse_config;
772
773 case LEXEME_STRING:
774 if (!lexeme_ring_buffer_try_put(&parser->buffer, lexeme))
775 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); })
;
776
777 return parse_config;
778
779 case LEXEME_CLOSE_BRACKET:
780 return parse_section_end;
781
782 case LEXEME_EOF:
783 if (config_from_parser(parser)->opened_brackets)
784 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); })
;
785
786 if (!lexeme_ring_buffer_empty(&parser->buffer))
787 return INTERNAL_ERROR(parser, "premature EOF")({ config_error(config_from_parser(parser), "%s" "premature EOF"
, "Internal error: "); ((void*)0); })
;
788
789 break;
790
791 case LEXEME_VARIABLE:
792 case LEXEME_VARIABLE_DEFAULT:
793 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); })
794 (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); })
;
795
796 case TOTAL_LEXEMES:
797 __builtin_unreachable();
798 }
799
800 return NULL((void*)0);
801}
802
803static const struct config_line *parser_next_internal(struct parser *parser)
804{
805 while (parser->state) {
806 const struct config_line *line;
807
808 if ((line = config_ring_buffer_get_ptr_or_null(&parser->items)))
809 return line;
810
811 lwan_strbuf_reset(&parser->strbuf);
812
813 parser->state = parser->state(parser);
814 }
815
816 return config_ring_buffer_get_ptr_or_null(&parser->items);
817}
818
819static bool_Bool parse_constants(struct config *config, const struct config_line *l)
820{
821 while ((l = config_read_line(config))) {
11
Loop condition is true. Entering loop body
17
Execution continues on line 821
18
Potential leak of memory pointed to by 'v'
822 switch (l->type) {
12
Control jumps to 'case CONFIG_LINE_TYPE_LINE:' at line 823
823 case CONFIG_LINE_TYPE_LINE: {
824 char *k = strdup(l->key);
825 char *v = strdup(l->value);
13
Memory is allocated
826
827 if (!k || !v)
14
Assuming 'k' is non-null
15
Assuming 'v' is non-null
16
Taking false branch
828 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"
, 828, __FUNCTION__, "Can't allocate memory for constant")
;
829
830 hash_add(config->constants, k, v);
831 break;
832 }
833
834 case CONFIG_LINE_TYPE_SECTION_END:
835 return true1;
836
837 case CONFIG_LINE_TYPE_SECTION:
838 config_error(config, "Constants section can't be nested");
839 return false0;
840 }
841 }
842
843 return true1;
844}
845
846static const struct config_line *parser_next(struct parser *parser)
847{
848 while (true1) {
7
Loop condition is true. Entering loop body
849 const struct config_line *l = parser_next_internal(parser);
850
851 if (!l
7.1
'l' is non-null
)
852 return NULL((void*)0);
853
854 if (l->type == CONFIG_LINE_TYPE_SECTION && streq(l->key, "constants")) {
8
Assuming field 'type' is equal to CONFIG_LINE_TYPE_SECTION
9
Taking true branch
855 struct config *config = config_from_parser(parser);
856
857 if (parse_constants(config, l))
10
Calling 'parse_constants'
858 continue;
859
860 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); }
)
861 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); }
)
;
862 }
863
864 return l;
865 }
866}
867
868static struct config *
869config_open_path(const char *path, void **data, size_t *size)
870{
871 struct config *config;
872 struct stat st;
873 void *mapped;
874 int fd;
875
876 fd = open(path, O_RDONLY00 | O_CLOEXEC02000000);
877 if (fd < 0) {
878 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"
, 878, __FUNCTION__, "Could not open configuration file: %s",
path)
;
879 return NULL((void*)0);
880 }
881
882 if (fstat(fd, &st) < 0) {
883 close(fd);
884 return NULL((void*)0);
885 }
886
887 mapped = mmap(NULL((void*)0), (size_t)st.st_size, PROT_READ0x1, MAP_PRIVATE0x02, fd, 0);
888 close(fd);
889 if (mapped == MAP_FAILED((void *) -1))
890 return NULL((void*)0);
891
892 config = malloc(sizeof(*config));
893 if (!config) {
894 munmap(mapped, (size_t)st.st_size);
895 return NULL((void*)0);
896 }
897
898 *data = config->mapped.addr = mapped;
899 *size = config->mapped.sz = (size_t)st.st_size;
900
901 return config;
902}
903
904static struct config *
905config_init_data(struct config *config, const void *data, size_t len)
906{
907 config->parser = (struct parser){
908 .state = parse_config,
909 .lexer =
910 {
911 .state = lex_config,
912 .pos = data,
913 .start = data,
914 .end = (char *)data + len,
915 .cur_line = 1,
916 },
917 };
918
919 config->error_message = NULL((void*)0);
920 config->opened_brackets = 0;
921
922 config->constants = hash_str_new(free, free);
923
924 lwan_strbuf_init(&config->parser.strbuf);
925 config_ring_buffer_init(&config->parser.items);
926 lexeme_ring_buffer_init(&config->parser.buffer);
927
928 return config;
929}
930
931struct config *config_open(const char *path)
932{
933 struct config *config;
934 void *data;
935 size_t len;
936
937 config = config_open_path(path, &data, &len);
938 return config ? config_init_data(config, data, len) : NULL((void*)0);
939}
940
941#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
942struct config *config_open_for_fuzzing(const uint8_t *data, size_t len)
943{
944 struct config *config = malloc(sizeof(*config));
945
946 if (config) {
947 config->mapped.addr = NULL((void*)0);
948 config->mapped.sz = 0;
949
950 return config_init_data(config, data, len - 1);
951 }
952
953 return NULL((void*)0);
954}
955#endif
956
957void config_close(struct config *config)
958{
959 if (!config)
960 return;
961
962#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
963 if (config->mapped.addr)
964 munmap(config->mapped.addr, config->mapped.sz);
965#endif
966
967 hash_unref(config->constants);
968
969 free(config->error_message);
970 lwan_strbuf_free(&config->parser.strbuf);
971 free(config);
972}
973
974const struct config_line *config_read_line(struct config *conf)
975{
976 return conf->error_message ? NULL((void*)0) : parser_next(&conf->parser);
977}
978
979static bool_Bool find_section_end(struct config *config)
980{
981 const struct config_line *line;
982 int cur_level = 1;
983
984 if (config->error_message)
4
Assuming field 'error_message' is null
5
Taking false branch
985 return false0;
986
987 while ((line = parser_next(&config->parser))) {
6
Calling 'parser_next'
988 if (line->type == CONFIG_LINE_TYPE_SECTION) {
989 cur_level++;
990 } else if (line->type == CONFIG_LINE_TYPE_SECTION_END) {
991 cur_level--;
992
993 if (!cur_level)
994 return true1;
995 }
996 }
997
998 return false0;
999}
1000
1001struct config *config_isolate_section(struct config *current_conf,
1002 const struct config_line *current_line)
1003{
1004 struct lexer *lexer;
1005 struct config *isolated;
1006 const char *pos;
1007
1008 if (current_line->type != CONFIG_LINE_TYPE_SECTION)
1009 return NULL((void*)0);
1010
1011 isolated = malloc(sizeof(*isolated));
1012 if (!isolated)
1013 return NULL((void*)0);
1014
1015 memcpy(isolated, current_conf, sizeof(*isolated));
1016 lwan_strbuf_init(&isolated->parser.strbuf);
1017
1018 isolated->constants = hash_ref(current_conf->constants);
1019
1020 isolated->mapped.addr = NULL((void*)0);
1021 isolated->mapped.sz = 0;
1022 /* Keep opened_brackets from the original */
1023
1024 lexer = &isolated->parser.lexer;
1025 lexer->start = lexer->pos;
1026
1027 pos = isolated->parser.lexer.pos;
1028 if (!find_section_end(isolated)) {
1029 config_error(current_conf,
1030 "Could not find section end while trying to isolate: %s",
1031 config_last_error(isolated));
1032
1033 hash_unref(isolated->constants);
1034 lwan_strbuf_free(&isolated->parser.strbuf);
1035 free(isolated);
1036
1037 return NULL((void*)0);
1038 }
1039
1040 lexer->end = lexer->pos;
1041 lexer->start = lexer->pos = pos;
1042
1043 return isolated;
1044}
1045
1046bool_Bool config_skip_section(struct config *conf, const struct config_line *line)
1047{
1048 if (line->type != CONFIG_LINE_TYPE_SECTION)
1
Assuming field 'type' is equal to CONFIG_LINE_TYPE_SECTION
2
Taking false branch
1049 return false0;
1050
1051 return find_section_end(conf);
3
Calling 'find_section_end'
1052}
1053
1054const char *config_last_error(struct config *conf)
1055{
1056 return conf->error_message;
1057}
1058
1059int config_cur_line(struct config *conf)
1060{
1061 return conf->parser.lexer.cur_line;
1062}