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