clang -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name renderer.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model static -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/local/clang-7.0.0/lib/clang/7.0.0 -D HAVE_CONFIG_H -I . -I /home/travis/build/blogc/blogc -internal-isystem /usr/local/include -internal-isystem /usr/local/clang-7.0.0/lib/clang/7.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -fdebug-compilation-dir /home/travis/build/blogc/blogc/build -ferror-limit 19 -fmessage-length 0 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /home/travis/build/blogc/blogc/build/reports/2018-12-20-003316-8439-1 -x c /home/travis/build/blogc/blogc/src/blogc/renderer.c -faddrsig
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include <stdbool.h> |
10 | #include <stddef.h> |
11 | #include <stdio.h> |
12 | #include <stdlib.h> |
13 | #include <string.h> |
14 | #include "datetime-parser.h" |
15 | #include "template-parser.h" |
16 | #include "renderer.h" |
17 | #include "../common/error.h" |
18 | #include "../common/utils.h" |
19 | |
20 | |
21 | const char* |
22 | blogc_get_variable(const char *name, bc_trie_t *global, bc_trie_t *local) |
23 | { |
24 | const char *rv = NULL((void*)0); |
25 | if (local != NULL((void*)0)) { |
26 | rv = bc_trie_lookup(local, name); |
27 | if (rv != NULL((void*)0)) |
28 | return rv; |
29 | } |
30 | if (global != NULL((void*)0)) |
31 | rv = bc_trie_lookup(global, name); |
32 | return rv; |
33 | } |
34 | |
35 | |
36 | char* |
37 | blogc_format_date(const char *date, bc_trie_t *global, bc_trie_t *local) |
38 | { |
39 | const char *date_format = blogc_get_variable("DATE_FORMAT", global, local); |
40 | if (date == NULL((void*)0)) |
41 | return NULL((void*)0); |
42 | if (date_format == NULL((void*)0)) |
43 | return bc_strdup(date); |
44 | |
45 | bc_error_t *err = NULL((void*)0); |
46 | char *rv = blogc_convert_datetime(date, date_format, &err); |
47 | if (err != NULL((void*)0)) { |
48 | bc_error_print(err, "blogc"); |
49 | bc_error_free(err); |
50 | return bc_strdup(date); |
51 | } |
52 | return rv; |
53 | } |
54 | |
55 | |
56 | char* |
57 | blogc_format_variable(const char *name, bc_trie_t *global, bc_trie_t *local, |
58 | bc_slist_t *foreach_var) |
59 | { |
60 | |
61 | const char *value = blogc_get_variable(name, global, local); |
62 | if (value != NULL((void*)0)) |
63 | return bc_strdup(value); |
64 | |
65 | |
66 | if (0 == strcmp(name, "FOREACH_ITEM")) { |
67 | if (foreach_var != NULL((void*)0) && foreach_var->data != NULL((void*)0)) { |
68 | return bc_strdup(foreach_var->data); |
69 | } |
70 | return NULL((void*)0); |
71 | } |
72 | |
73 | char *var = bc_strdup(name); |
74 | |
75 | size_t i; |
76 | size_t last = strlen(var); |
77 | |
78 | long int len = -1; |
79 | |
80 | |
81 | for (i = last - 1; i > 0 && var[i] >= '0' && var[i] <= '9'; i--); |
82 | |
83 | if (var[i] == '_' && (i + 1) < last) { |
84 | char *endptr; |
85 | len = strtol(var + i + 1, &endptr, 10); |
86 | if (*endptr != '\0') { |
87 | fprintf(stderrstderr, "warning: invalid variable size for '%s', " |
88 | "ignoring.\n", var); |
89 | len = -1; |
90 | } |
91 | else { |
92 | var[i] = '\0'; |
93 | } |
94 | } |
95 | |
96 | bool_Bool must_format = false0; |
97 | |
98 | if (bc_str_ends_with(var, "_FORMATTED")) { |
99 | var[strlen(var) - 10] = '\0'; |
100 | must_format = true1; |
101 | } |
102 | |
103 | if ((0 == strcmp(var, "FOREACH_ITEM")) && |
104 | (foreach_var != NULL((void*)0) && foreach_var->data != NULL((void*)0))) |
105 | value = foreach_var->data; |
106 | else |
107 | value = blogc_get_variable(var, global, local); |
108 | |
109 | if (value == NULL((void*)0)) { |
110 | free(var); |
111 | return NULL((void*)0); |
112 | } |
113 | |
114 | char *rv = NULL((void*)0); |
115 | |
116 | if (must_format) { |
117 | if (bc_str_starts_with(name, "DATE_")) { |
118 | rv = blogc_format_date(value, global, local); |
119 | } |
120 | else { |
121 | fprintf(stderrstderr, "warning: no formatter found for '%s', " |
122 | "ignoring.\n", var); |
123 | rv = bc_strdup(value); |
124 | } |
125 | } |
126 | else { |
127 | rv = bc_strdup(value); |
128 | } |
129 | |
130 | free(var); |
131 | |
132 | if (len > 0) { |
133 | char *tmp = bc_strndup(rv, len); |
134 | free(rv); |
135 | rv = tmp; |
136 | } |
137 | |
138 | return rv; |
139 | } |
140 | |
141 | |
142 | bc_slist_t* |
143 | blogc_split_list_variable(const char *name, bc_trie_t *global, bc_trie_t *local) |
144 | { |
145 | const char *value = blogc_get_variable(name, global, local); |
146 | if (value == NULL((void*)0)) |
147 | return NULL((void*)0); |
148 | |
149 | bc_slist_t *rv = NULL((void*)0); |
150 | |
151 | char **tmp = bc_str_split(value, ' ', 0); |
152 | for (size_t i = 0; tmp[i] != NULL((void*)0); i++) { |
153 | if (tmp[i][0] != '\0') |
154 | rv = bc_slist_append(rv, tmp[i]); |
155 | else |
156 | free(tmp[i]); |
157 | } |
158 | free(tmp); |
159 | |
160 | return rv; |
161 | } |
162 | |
163 | |
164 | char* |
165 | blogc_render(bc_slist_t *tmpl, bc_slist_t *sources, bc_trie_t *config, bool_Bool listing) |
166 | { |
167 | if (tmpl == NULL((void*)0)) |
| 1 | Assuming 'tmpl' is not equal to NULL | |
|
| |
168 | return NULL((void*)0); |
169 | |
170 | bc_slist_t *current_source = NULL((void*)0); |
171 | bc_slist_t *listing_start = NULL((void*)0); |
172 | |
173 | bc_string_t *str = bc_string_new(); |
174 | |
175 | bc_trie_t *tmp_source = NULL((void*)0); |
176 | char *config_value = NULL((void*)0); |
177 | char *defined = NULL((void*)0); |
178 | |
179 | size_t if_count = 0; |
180 | |
181 | bc_slist_t *foreach_var = NULL((void*)0); |
182 | bc_slist_t *foreach_var_start = NULL((void*)0); |
183 | bc_slist_t *foreach_start = NULL((void*)0); |
184 | |
185 | bool_Bool if_not = false0; |
186 | bool_Bool inside_block = false0; |
187 | bool_Bool evaluate = false0; |
188 | bool_Bool valid_else = false0; |
189 | |
190 | int cmp = 0; |
191 | |
192 | bc_slist_t *tmp = tmpl; |
193 | while (tmp != NULL((void*)0)) { |
| 3 | | Loop condition is true. Entering loop body | |
|
| 17 | | Assuming 'tmp' is not equal to NULL | |
|
| 18 | | Loop condition is true. Entering loop body | |
|
194 | blogc_template_node_t *node = tmp->data; |
195 | |
196 | switch (node->type) { |
| 4 | | Control jumps to 'case BLOGC_TEMPLATE_NODE_BLOCK:' at line 203 | |
|
| 19 | | Control jumps to 'case BLOGC_TEMPLATE_NODE_BLOCK:' at line 203 | |
|
197 | |
198 | case BLOGC_TEMPLATE_NODE_CONTENT: |
199 | if (node->data[0] != NULL((void*)0)) |
200 | bc_string_append(str, node->data[0]); |
201 | break; |
202 | |
203 | case BLOGC_TEMPLATE_NODE_BLOCK: |
204 | inside_block = true1; |
205 | if_count = 0; |
206 | if (0 == strcmp("entry", node->data[0])) { |
| 5 | | Assuming the condition is false | |
|
| |
| |
207 | if (listing) { |
| 21 | | Assuming 'listing' is 0 | |
|
| |
208 | |
209 | |
210 | |
211 | while (node->type != BLOGC_TEMPLATE_NODE_ENDBLOCK) { |
212 | tmp = tmp->next; |
213 | node = tmp->data; |
214 | } |
215 | break; |
216 | } |
217 | current_source = sources; |
| 23 | | Null pointer value stored to 'current_source' | |
|
218 | tmp_source = current_source->data; |
| 24 | | Access to field 'data' results in a dereference of a null pointer (loaded from variable 'current_source') |
|
219 | } |
220 | else if ((0 == strcmp("listing", node->data[0])) || |
| 7 | | Assuming the condition is false | |
|
| |
221 | (0 == strcmp("listing_once", node->data[0]))) { |
| 8 | | Assuming the condition is false | |
|
222 | if (!listing) { |
223 | |
224 | |
225 | |
226 | while (node->type != BLOGC_TEMPLATE_NODE_ENDBLOCK) { |
227 | tmp = tmp->next; |
228 | node = tmp->data; |
229 | } |
230 | break; |
231 | } |
232 | } |
233 | if (0 == strcmp("listing", node->data[0])) { |
| |
234 | if (sources == NULL((void*)0)) { |
| 11 | | Assuming 'sources' is equal to NULL | |
|
| |
235 | |
236 | |
237 | |
238 | while (node->type != BLOGC_TEMPLATE_NODE_ENDBLOCK) { |
| 13 | | Loop condition is true. Entering loop body | |
|
| 14 | | Assuming the condition is false | |
|
| 15 | | Loop condition is false. Execution continues on line 242 | |
|
239 | tmp = tmp->next; |
240 | node = tmp->data; |
241 | } |
242 | break; |
| 16 | | Execution continues on line 452 | |
|
243 | } |
244 | if (current_source == NULL((void*)0)) { |
245 | listing_start = tmp; |
246 | current_source = sources; |
247 | } |
248 | tmp_source = current_source->data; |
249 | } |
250 | break; |
251 | |
252 | case BLOGC_TEMPLATE_NODE_VARIABLE: |
253 | if (node->data[0] != NULL((void*)0)) { |
254 | config_value = blogc_format_variable(node->data[0], |
255 | config, inside_block ? tmp_source : NULL((void*)0), foreach_var); |
256 | if (config_value != NULL((void*)0)) { |
257 | bc_string_append(str, config_value); |
258 | free(config_value); |
259 | config_value = NULL((void*)0); |
260 | break; |
261 | } |
262 | } |
263 | break; |
264 | |
265 | case BLOGC_TEMPLATE_NODE_ENDBLOCK: |
266 | inside_block = false0; |
267 | if (listing_start != NULL((void*)0) && current_source != NULL((void*)0)) { |
268 | current_source = current_source->next; |
269 | if (current_source != NULL((void*)0)) { |
270 | tmp = listing_start; |
271 | continue; |
272 | } |
273 | else |
274 | listing_start = NULL((void*)0); |
275 | } |
276 | break; |
277 | |
278 | case BLOGC_TEMPLATE_NODE_IFNDEF: |
279 | if_not = true1; |
280 | |
281 | case BLOGC_TEMPLATE_NODE_IF: |
282 | case BLOGC_TEMPLATE_NODE_IFDEF: |
283 | if_count = 0; |
284 | defined = NULL((void*)0); |
285 | if (node->data[0] != NULL((void*)0)) |
286 | defined = blogc_format_variable(node->data[0], config, |
287 | inside_block ? tmp_source : NULL((void*)0), foreach_var); |
288 | evaluate = false0; |
289 | if (node->op != 0) { |
290 | |
291 | |
292 | |
293 | char *defined2 = NULL((void*)0); |
294 | if (node->data[1] != NULL((void*)0)) { |
295 | if ((strlen(node->data[1]) >= 2) && |
296 | (node->data[1][0] == '"') && |
297 | (node->data[1][strlen(node->data[1]) - 1] == '"')) |
298 | { |
299 | defined2 = bc_strndup(node->data[1] + 1, |
300 | strlen(node->data[1]) - 2); |
301 | } |
302 | else { |
303 | defined2 = blogc_format_variable(node->data[1], |
304 | config, inside_block ? tmp_source : NULL((void*)0), |
305 | foreach_var); |
306 | } |
307 | } |
308 | |
309 | if (defined != NULL((void*)0) && defined2 != NULL((void*)0)) { |
310 | cmp = strcmp(defined, defined2); |
311 | if (cmp != 0 && node->op & BLOGC_TEMPLATE_OP_NEQ) |
312 | evaluate = true1; |
313 | else if (cmp == 0 && node->op & BLOGC_TEMPLATE_OP_EQ) |
314 | evaluate = true1; |
315 | else if (cmp < 0 && node->op & BLOGC_TEMPLATE_OP_LT) |
316 | evaluate = true1; |
317 | else if (cmp > 0 && node->op & BLOGC_TEMPLATE_OP_GT) |
318 | evaluate = true1; |
319 | } |
320 | |
321 | free(defined2); |
322 | } |
323 | else { |
324 | if (if_not && defined == NULL((void*)0)) |
325 | evaluate = true1; |
326 | if (!if_not && defined != NULL((void*)0)) |
327 | evaluate = true1; |
328 | } |
329 | if (!evaluate) { |
330 | |
331 | |
332 | |
333 | |
334 | while (1) { |
335 | tmp = tmp->next; |
336 | node = tmp->data; |
337 | if ((node->type == BLOGC_TEMPLATE_NODE_IF) || |
338 | (node->type == BLOGC_TEMPLATE_NODE_IFDEF) || |
339 | (node->type == BLOGC_TEMPLATE_NODE_IFNDEF)) |
340 | { |
341 | if_count++; |
342 | continue; |
343 | } |
344 | if ((node->type == BLOGC_TEMPLATE_NODE_ELSE) && |
345 | (if_count == 0)) |
346 | { |
347 | |
348 | |
349 | |
350 | |
351 | |
352 | valid_else = true1; |
353 | break; |
354 | } |
355 | if (node->type == BLOGC_TEMPLATE_NODE_ENDIF) { |
356 | if (if_count > 0) { |
357 | if_count--; |
358 | continue; |
359 | } |
360 | break; |
361 | } |
362 | } |
363 | } |
364 | else { |
365 | valid_else = false0; |
366 | } |
367 | free(defined); |
368 | defined = NULL((void*)0); |
369 | if_not = false0; |
370 | break; |
371 | |
372 | case BLOGC_TEMPLATE_NODE_ELSE: |
373 | if_count = 0; |
374 | if (!valid_else) { |
375 | |
376 | |
377 | |
378 | |
379 | while (1) { |
380 | tmp = tmp->next; |
381 | node = tmp->data; |
382 | if ((node->type == BLOGC_TEMPLATE_NODE_IF) || |
383 | (node->type == BLOGC_TEMPLATE_NODE_IFDEF) || |
384 | (node->type == BLOGC_TEMPLATE_NODE_IFNDEF)) |
385 | { |
386 | if_count++; |
387 | continue; |
388 | } |
389 | |
390 | |
391 | if (node->type == BLOGC_TEMPLATE_NODE_ENDIF) { |
392 | if (if_count > 0) { |
393 | if_count--; |
394 | continue; |
395 | } |
396 | break; |
397 | } |
398 | } |
399 | } |
400 | valid_else = false0; |
401 | break; |
402 | |
403 | case BLOGC_TEMPLATE_NODE_ENDIF: |
404 | |
405 | |
406 | valid_else = false0; |
407 | if (if_count > 0) |
408 | if_count--; |
409 | break; |
410 | |
411 | case BLOGC_TEMPLATE_NODE_FOREACH: |
412 | if (foreach_var_start == NULL((void*)0)) { |
413 | if (node->data[0] != NULL((void*)0)) |
414 | foreach_var_start = blogc_split_list_variable(node->data[0], |
415 | config, inside_block ? tmp_source : NULL((void*)0)); |
416 | |
417 | if (foreach_var_start != NULL((void*)0)) { |
418 | foreach_var = foreach_var_start; |
419 | foreach_start = tmp; |
420 | } |
421 | else { |
422 | |
423 | |
424 | |
425 | while (node->type != BLOGC_TEMPLATE_NODE_ENDFOREACH) { |
426 | tmp = tmp->next; |
427 | node = tmp->data; |
428 | } |
429 | break; |
430 | } |
431 | } |
432 | |
433 | if (foreach_var == NULL((void*)0)) { |
434 | foreach_start = tmp; |
435 | foreach_var = foreach_var_start; |
436 | } |
437 | break; |
438 | |
439 | case BLOGC_TEMPLATE_NODE_ENDFOREACH: |
440 | if (foreach_start != NULL((void*)0) && foreach_var != NULL((void*)0)) { |
441 | foreach_var = foreach_var->next; |
442 | if (foreach_var != NULL((void*)0)) { |
443 | tmp = foreach_start; |
444 | continue; |
445 | } |
446 | } |
447 | foreach_start = NULL((void*)0); |
448 | bc_slist_free_full(foreach_var_start, free); |
449 | foreach_var_start = NULL((void*)0); |
450 | break; |
451 | } |
452 | tmp = tmp->next; |
453 | } |
454 | |
455 | |
456 | |
457 | |
458 | return bc_string_free(str, false0); |
459 | } |