File: | lib/lwan-config.c |
Warning: | line 821, column 17 Potential leak of memory pointed to by 'v' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
69 | enum 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 | ||||
76 | struct lexeme { | |||
77 | enum lexeme_type type; | |||
78 | struct { | |||
79 | const char *value; | |||
80 | size_t len; | |||
81 | } value; | |||
82 | }; | |||
83 | ||||
84 | DEFINE_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++)]; } | |||
85 | DEFINE_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 | ||||
87 | struct lexer { | |||
88 | void *(*state)(struct lexer *); | |||
89 | const char *start, *pos, *end; | |||
90 | struct lexeme_ring_buffer buffer; | |||
91 | int cur_line; | |||
92 | }; | |||
93 | ||||
94 | struct 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 | ||||
102 | struct 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 | ||||
113 | unsigned 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 | ||||
159 | long 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 | ||||
179 | long 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 | ||||
189 | int 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 | ||||
199 | bool_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 | ||||
215 | LWAN_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 | ||||
232 | bool_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 | ||||
254 | static 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 | ||||
260 | static size_t current_len(struct lexer *lexer) | |||
261 | { | |||
262 | return (size_t)(lexer->pos - lexer->start); | |||
263 | } | |||
264 | ||||
265 | static 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 | ||||
274 | static 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 | ||||
290 | static void ignore(struct lexer *lexer) | |||
291 | { | |||
292 | lexer->start = lexer->pos; | |||
293 | } | |||
294 | ||||
295 | static void advance_n(struct lexer *lexer, size_t n) | |||
296 | { | |||
297 | lexer->pos += n; | |||
298 | ignore(lexer); | |||
299 | } | |||
300 | ||||
301 | static void backup(struct lexer *lexer) | |||
302 | { | |||
303 | lexer->pos--; | |||
304 | ||||
305 | if (*lexer->pos == '\n') | |||
306 | lexer->cur_line--; | |||
307 | } | |||
308 | ||||
309 | static int peek(struct lexer *lexer) | |||
310 | { | |||
311 | int chr = next(lexer); | |||
312 | ||||
313 | backup(lexer); | |||
314 | ||||
315 | return chr; | |||
316 | } | |||
317 | ||||
318 | static size_t remaining(struct lexer *lexer) | |||
319 | { | |||
320 | return (size_t)(lexer->end - lexer->pos); | |||
321 | } | |||
322 | ||||
323 | static void *lex_config(struct lexer *lexer); | |||
324 | static void *lex_variable(struct lexer *lexer); | |||
325 | ||||
326 | static 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 | ||||
331 | static 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 | ||||
354 | static 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 | ||||
359 | static 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 | ||||
366 | static 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 | ||||
374 | static 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 | ||||
392 | static bool_Bool is_variable(int chr) | |||
393 | { | |||
394 | return isalpha(chr)((*__ctype_b_loc ())[(int) ((chr))] & (unsigned short int ) _ISalpha) || chr == '_'; | |||
395 | } | |||
396 | ||||
397 | static 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 | ||||
417 | static 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 | ||||
453 | static bool_Bool is_comment(int chr) | |||
454 | { | |||
455 | return chr != '\0' && chr != '\n'; | |||
456 | } | |||
457 | ||||
458 | static void *lex_comment(struct lexer *lexer) | |||
459 | { | |||
460 | while (is_comment(next(lexer))) | |||
461 | ; | |||
462 | backup(lexer); | |||
463 | return lex_config; | |||
464 | } | |||
465 | ||||
466 | static 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 | ||||
528 | static 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 | ||||
542 | static void *parse_config(struct parser *parser); | |||
543 | static void *parse_section_end(struct parser *parser); | |||
544 | ||||
545 | #define ENV_VAR_NAME_LEN_MAX64 64 | |||
546 | ||||
547 | static __attribute__((noinline)) const char * | |||
548 | get_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 | ||||
561 | static 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 | ||||
671 | static 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 | ||||
705 | static 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 | ||||
721 | static 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 | ||||
742 | static 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 | ||||
803 | static 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 | ||||
819 | static bool_Bool parse_constants(struct config *config, const struct config_line *l) | |||
820 | { | |||
821 | while ((l = config_read_line(config))) { | |||
| ||||
822 | switch (l->type) { | |||
823 | case CONFIG_LINE_TYPE_LINE: { | |||
824 | char *k = strdup(l->key); | |||
825 | char *v = strdup(l->value); | |||
826 | ||||
827 | if (!k || !v) | |||
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 | ||||
846 | static const struct config_line *parser_next(struct parser *parser) | |||
847 | { | |||
848 | while (true1) { | |||
849 | const struct config_line *l = parser_next_internal(parser); | |||
850 | ||||
851 | if (!l
| |||
852 | return NULL((void*)0); | |||
853 | ||||
854 | if (l->type == CONFIG_LINE_TYPE_SECTION && streq(l->key, "constants")) { | |||
855 | struct config *config = config_from_parser(parser); | |||
856 | ||||
857 | if (parse_constants(config, l)) | |||
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 | ||||
868 | static struct config * | |||
869 | config_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 | ||||
904 | static struct config * | |||
905 | config_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 | ||||
931 | struct 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) | |||
942 | struct 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 | ||||
957 | void 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 | ||||
974 | const struct config_line *config_read_line(struct config *conf) | |||
975 | { | |||
976 | return conf->error_message ? NULL((void*)0) : parser_next(&conf->parser); | |||
977 | } | |||
978 | ||||
979 | static 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) | |||
985 | return false0; | |||
986 | ||||
987 | while ((line = parser_next(&config->parser))) { | |||
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 | ||||
1001 | struct 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 | ||||
1046 | bool_Bool config_skip_section(struct config *conf, const struct config_line *line) | |||
1047 | { | |||
1048 | if (line->type != CONFIG_LINE_TYPE_SECTION) | |||
| ||||
1049 | return false0; | |||
1050 | ||||
1051 | return find_section_end(conf); | |||
1052 | } | |||
1053 | ||||
1054 | const char *config_last_error(struct config *conf) | |||
1055 | { | |||
1056 | return conf->error_message; | |||
1057 | } | |||
1058 | ||||
1059 | int config_cur_line(struct config *conf) | |||
1060 | { | |||
1061 | return conf->parser.lexer.cur_line; | |||
1062 | } |