File: | lib/lwan-strbuf.c |
Warning: | line 215, column 18 The left operand of '&' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * lwan - web server | |||
3 | * Copyright (c) 2012 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, | |||
18 | * USA. | |||
19 | */ | |||
20 | ||||
21 | #define _GNU_SOURCE | |||
22 | #include <errno(*__errno_location ()).h> | |||
23 | #include <fcntl.h> | |||
24 | #include <limits.h> | |||
25 | #include <stdarg.h> | |||
26 | #include <stddef.h> | |||
27 | #include <stdlib.h> | |||
28 | #include <string.h> | |||
29 | #include <sys/stat.h> | |||
30 | ||||
31 | #include "lwan-private.h" | |||
32 | ||||
33 | static const unsigned int BUFFER_MALLOCD = 1 << 0; | |||
34 | static const unsigned int STRBUF_MALLOCD = 1 << 1; | |||
35 | static const unsigned int BUFFER_FIXED = 1 << 2; | |||
36 | static const unsigned int GROW_BUFFER_FAILED = 1 << 3; | |||
37 | ||||
38 | bool_Bool lwan_strbuf_has_grow_buffer_failed_flag(const struct lwan_strbuf *s) | |||
39 | { | |||
40 | return s->flags & GROW_BUFFER_FAILED; | |||
41 | } | |||
42 | ||||
43 | static inline size_t align_size(size_t unaligned_size) | |||
44 | { | |||
45 | const size_t aligned_size = lwan_nextpow2(unaligned_size); | |||
46 | ||||
47 | if (UNLIKELY(unaligned_size >= aligned_size)__builtin_expect(((unaligned_size >= aligned_size)), (0))) | |||
48 | return 0; | |||
49 | ||||
50 | return aligned_size; | |||
51 | } | |||
52 | ||||
53 | static ALWAYS_INLINEinline __attribute__((always_inline)) | |||
54 | bool_Bool grow_buffer_if_needed_internal(struct lwan_strbuf *s, size_t size) | |||
55 | { | |||
56 | if (s->flags & BUFFER_FIXED) | |||
57 | return size < s->capacity; | |||
58 | ||||
59 | if (!(s->flags & BUFFER_MALLOCD)) { | |||
60 | const size_t aligned_size = align_size(LWAN_MAX(size + 1, s->used)({ const __typeof__((size + 1) + 0) lwan_tmp_id4 = (size + 1) ; const __typeof__((s->used) + 0) lwan_tmp_id5 = (s->used ); lwan_tmp_id4 < lwan_tmp_id5 ? lwan_tmp_id5 : lwan_tmp_id4 ; })); | |||
61 | if (UNLIKELY(!aligned_size)__builtin_expect(((!aligned_size)), (0))) | |||
62 | return false0; | |||
63 | ||||
64 | char *buffer = malloc(aligned_size); | |||
65 | if (UNLIKELY(!buffer)__builtin_expect(((!buffer)), (0))) | |||
66 | return false0; | |||
67 | ||||
68 | memcpy(buffer, s->buffer, s->used); | |||
69 | buffer[s->used + 1] = '\0'; | |||
70 | ||||
71 | s->flags |= BUFFER_MALLOCD; | |||
72 | s->buffer = buffer; | |||
73 | s->capacity = aligned_size; | |||
74 | ||||
75 | return true1; | |||
76 | } | |||
77 | ||||
78 | if (UNLIKELY(s->capacity < size)__builtin_expect(((s->capacity < size)), (0))) { | |||
79 | char *buffer; | |||
80 | const size_t aligned_size = align_size(size + 1); | |||
81 | ||||
82 | if (UNLIKELY(!aligned_size)__builtin_expect(((!aligned_size)), (0))) | |||
83 | return false0; | |||
84 | ||||
85 | if (s->used == 0) { | |||
86 | /* Avoid memcpy() inside realloc() if we were not using the | |||
87 | * allocated buffer at this point. */ | |||
88 | buffer = malloc(aligned_size); | |||
89 | ||||
90 | if (UNLIKELY(!buffer)__builtin_expect(((!buffer)), (0))) | |||
91 | return false0; | |||
92 | ||||
93 | free(s->buffer); | |||
94 | buffer[0] = '\0'; | |||
95 | } else { | |||
96 | buffer = realloc(s->buffer, aligned_size); | |||
97 | ||||
98 | if (UNLIKELY(!buffer)__builtin_expect(((!buffer)), (0))) | |||
99 | return false0; | |||
100 | } | |||
101 | ||||
102 | s->buffer = buffer; | |||
103 | s->capacity = aligned_size; | |||
104 | } | |||
105 | ||||
106 | return true1; | |||
107 | } | |||
108 | ||||
109 | static bool_Bool grow_buffer_if_needed(struct lwan_strbuf *s, size_t size) | |||
110 | { | |||
111 | if (UNLIKELY(!grow_buffer_if_needed_internal(s, size))__builtin_expect(((!grow_buffer_if_needed_internal(s, size))) , (0))) { | |||
112 | s->flags |= GROW_BUFFER_FAILED; | |||
113 | return false0; | |||
114 | } | |||
115 | ||||
116 | return true1; | |||
117 | } | |||
118 | ||||
119 | bool_Bool lwan_strbuf_init_with_size(struct lwan_strbuf *s, size_t size) | |||
120 | { | |||
121 | if (UNLIKELY(!s)__builtin_expect(((!s)), (0))) | |||
122 | return false0; | |||
123 | ||||
124 | *s = LWAN_STRBUF_STATIC_INIT(struct lwan_strbuf) { .buffer = "" }; | |||
125 | ||||
126 | if (size) { | |||
127 | if (UNLIKELY(!grow_buffer_if_needed(s, size))__builtin_expect(((!grow_buffer_if_needed(s, size))), (0))) | |||
128 | return false0; | |||
129 | ||||
130 | s->buffer[0] = '\0'; | |||
131 | } | |||
132 | ||||
133 | return true1; | |||
134 | } | |||
135 | ||||
136 | bool_Bool lwan_strbuf_init_with_fixed_buffer(struct lwan_strbuf *s, | |||
137 | void *buffer, | |||
138 | size_t size) | |||
139 | { | |||
140 | if (UNLIKELY(!s)__builtin_expect(((!s)), (0))) | |||
141 | return false0; | |||
142 | ||||
143 | *s = (struct lwan_strbuf) { | |||
144 | .capacity = size, | |||
145 | .used = 0, | |||
146 | .buffer = buffer, | |||
147 | .flags = BUFFER_FIXED, | |||
148 | }; | |||
149 | ||||
150 | return true1; | |||
151 | } | |||
152 | ||||
153 | ALWAYS_INLINEinline __attribute__((always_inline)) bool_Bool lwan_strbuf_init(struct lwan_strbuf *s) | |||
154 | { | |||
155 | return lwan_strbuf_init_with_size(s, 0); | |||
156 | } | |||
157 | ||||
158 | struct lwan_strbuf *lwan_strbuf_new_with_size(size_t size) | |||
159 | { | |||
160 | struct lwan_strbuf *s = malloc(sizeof(*s)); | |||
161 | ||||
162 | if (UNLIKELY(!lwan_strbuf_init_with_size(s, size))__builtin_expect(((!lwan_strbuf_init_with_size(s, size))), (0 ))) { | |||
163 | free(s); | |||
164 | ||||
165 | return NULL((void*)0); | |||
166 | } | |||
167 | ||||
168 | s->flags |= STRBUF_MALLOCD; | |||
169 | ||||
170 | return s; | |||
171 | } | |||
172 | ||||
173 | struct lwan_strbuf *lwan_strbuf_new_with_fixed_buffer(size_t size) | |||
174 | { | |||
175 | struct lwan_strbuf *s = malloc(sizeof(*s) + size + 1); | |||
176 | ||||
177 | if (UNLIKELY(!lwan_strbuf_init_with_fixed_buffer(s, s + 1, size))__builtin_expect(((!lwan_strbuf_init_with_fixed_buffer(s, s + 1, size))), (0))) { | |||
178 | free(s); | |||
179 | ||||
180 | return NULL((void*)0); | |||
181 | } | |||
182 | ||||
183 | s->flags |= STRBUF_MALLOCD; | |||
184 | ||||
185 | return s; | |||
186 | } | |||
187 | ||||
188 | ALWAYS_INLINEinline __attribute__((always_inline)) struct lwan_strbuf *lwan_strbuf_new(void) | |||
189 | { | |||
190 | return lwan_strbuf_new_with_size(0); | |||
191 | } | |||
192 | ||||
193 | ALWAYS_INLINEinline __attribute__((always_inline)) struct lwan_strbuf *lwan_strbuf_new_static(const char *str, | |||
194 | size_t size) | |||
195 | { | |||
196 | struct lwan_strbuf *s = malloc(sizeof(*s)); | |||
197 | ||||
198 | if (UNLIKELY(!s)__builtin_expect(((!s)), (0))) | |||
199 | return NULL((void*)0); | |||
200 | ||||
201 | *s = (struct lwan_strbuf) { | |||
202 | .flags = STRBUF_MALLOCD, | |||
203 | .buffer = (char *)str, | |||
204 | .used = size, | |||
205 | .capacity = size, | |||
206 | }; | |||
207 | ||||
208 | return s; | |||
209 | } | |||
210 | ||||
211 | void lwan_strbuf_free(struct lwan_strbuf *s) | |||
212 | { | |||
213 | if (UNLIKELY(!s)__builtin_expect(((!s)), (0))) | |||
214 | return; | |||
215 | if (s->flags & BUFFER_MALLOCD) { | |||
| ||||
216 | assert(!(s->flags & BUFFER_FIXED))((void) sizeof ((!(s->flags & BUFFER_FIXED)) ? 1 : 0), __extension__ ({ if (!(s->flags & BUFFER_FIXED)) ; else __assert_fail ("!(s->flags & BUFFER_FIXED)", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-strbuf.c" , 216, __extension__ __PRETTY_FUNCTION__); })); | |||
217 | free(s->buffer); | |||
218 | } | |||
219 | if (s->flags & STRBUF_MALLOCD) | |||
220 | free(s); | |||
221 | } | |||
222 | ||||
223 | bool_Bool lwan_strbuf_append_char(struct lwan_strbuf *s, const char c) | |||
224 | { | |||
225 | if (UNLIKELY(!grow_buffer_if_needed(s, s->used + 2))__builtin_expect(((!grow_buffer_if_needed(s, s->used + 2)) ), (0))) | |||
226 | return false0; | |||
227 | ||||
228 | s->buffer[s->used++] = c; | |||
229 | s->buffer[s->used] = '\0'; | |||
230 | ||||
231 | return true1; | |||
232 | } | |||
233 | ||||
234 | bool_Bool lwan_strbuf_append_str(struct lwan_strbuf *s1, const char *s2, size_t sz) | |||
235 | { | |||
236 | if (UNLIKELY(!grow_buffer_if_needed(s1, s1->used + sz + 2))__builtin_expect(((!grow_buffer_if_needed(s1, s1->used + sz + 2))), (0))) | |||
237 | return false0; | |||
238 | ||||
239 | memcpy(s1->buffer + s1->used, s2, sz); | |||
240 | s1->used += sz; | |||
241 | s1->buffer[s1->used] = '\0'; | |||
242 | ||||
243 | return true1; | |||
244 | } | |||
245 | ||||
246 | bool_Bool lwan_strbuf_set_static(struct lwan_strbuf *s1, const char *s2, size_t sz) | |||
247 | { | |||
248 | if (s1->flags & BUFFER_MALLOCD) | |||
249 | free(s1->buffer); | |||
250 | ||||
251 | s1->buffer = (char *)s2; | |||
252 | s1->used = s1->capacity = sz; | |||
253 | s1->flags &= ~(BUFFER_MALLOCD | BUFFER_FIXED); | |||
254 | ||||
255 | return true1; | |||
256 | } | |||
257 | ||||
258 | bool_Bool lwan_strbuf_set(struct lwan_strbuf *s1, const char *s2, size_t sz) | |||
259 | { | |||
260 | if (UNLIKELY(!grow_buffer_if_needed(s1, sz + 1))__builtin_expect(((!grow_buffer_if_needed(s1, sz + 1))), (0))) | |||
261 | return false0; | |||
262 | ||||
263 | memcpy(s1->buffer, s2, sz); | |||
264 | s1->used = sz; | |||
265 | s1->buffer[sz] = '\0'; | |||
266 | ||||
267 | return true1; | |||
268 | } | |||
269 | ||||
270 | static ALWAYS_INLINEinline __attribute__((always_inline)) bool_Bool | |||
271 | internal_printf(struct lwan_strbuf *s1, | |||
272 | bool_Bool (*save_str)(struct lwan_strbuf *, const char *, size_t), | |||
273 | const char *fmt, | |||
274 | va_list values) | |||
275 | { | |||
276 | char *s2; | |||
277 | int len; | |||
278 | ||||
279 | if (UNLIKELY((len = vasprintf(&s2, fmt, values)) < 0)__builtin_expect((((len = vasprintf(&s2, fmt, values)) < 0)), (0))) | |||
280 | return false0; | |||
281 | ||||
282 | bool_Bool success = save_str(s1, s2, (size_t)len); | |||
283 | free(s2); | |||
284 | ||||
285 | return success; | |||
286 | } | |||
287 | ||||
288 | bool_Bool lwan_strbuf_vprintf(struct lwan_strbuf *s, const char *fmt, va_list ap) | |||
289 | { | |||
290 | return internal_printf(s, lwan_strbuf_set, fmt, ap); | |||
291 | } | |||
292 | ||||
293 | bool_Bool lwan_strbuf_printf(struct lwan_strbuf *s, const char *fmt, ...) | |||
294 | { | |||
295 | bool_Bool could_printf; | |||
296 | va_list values; | |||
297 | ||||
298 | va_start(values, fmt)__builtin_va_start(values, fmt); | |||
299 | could_printf = lwan_strbuf_vprintf(s, fmt, values); | |||
300 | va_end(values)__builtin_va_end(values); | |||
301 | ||||
302 | return could_printf; | |||
303 | } | |||
304 | ||||
305 | bool_Bool lwan_strbuf_append_vprintf(struct lwan_strbuf *s, const char *fmt, va_list ap) | |||
306 | { | |||
307 | return internal_printf(s, lwan_strbuf_append_str, fmt, ap); | |||
308 | } | |||
309 | ||||
310 | bool_Bool lwan_strbuf_append_printf(struct lwan_strbuf *s, const char *fmt, ...) | |||
311 | { | |||
312 | bool_Bool could_printf; | |||
313 | va_list values; | |||
314 | ||||
315 | va_start(values, fmt)__builtin_va_start(values, fmt); | |||
316 | could_printf = lwan_strbuf_append_vprintf(s, fmt, values); | |||
317 | va_end(values)__builtin_va_end(values); | |||
318 | ||||
319 | return could_printf; | |||
320 | } | |||
321 | ||||
322 | bool_Bool lwan_strbuf_grow_to(struct lwan_strbuf *s, size_t new_size) | |||
323 | { | |||
324 | return grow_buffer_if_needed(s, new_size + 1); | |||
325 | } | |||
326 | ||||
327 | bool_Bool lwan_strbuf_grow_by(struct lwan_strbuf *s, size_t offset) | |||
328 | { | |||
329 | size_t new_size; | |||
330 | ||||
331 | if (__builtin_add_overflow(offset, s->used, &new_size)) | |||
332 | return false0; | |||
333 | ||||
334 | return lwan_strbuf_grow_to(s, new_size); | |||
335 | } | |||
336 | ||||
337 | void lwan_strbuf_reset(struct lwan_strbuf *s) | |||
338 | { | |||
339 | if (s->flags & BUFFER_MALLOCD) { | |||
340 | s->buffer[0] = '\0'; | |||
341 | } else { | |||
342 | s->buffer = ""; | |||
343 | s->capacity = 0; | |||
344 | } | |||
345 | ||||
346 | s->used = 0; | |||
347 | } | |||
348 | ||||
349 | void lwan_strbuf_reset_trim(struct lwan_strbuf *s, size_t trim_thresh) | |||
350 | { | |||
351 | if (s->flags & BUFFER_MALLOCD && s->capacity > trim_thresh) { | |||
352 | free(s->buffer); | |||
353 | s->flags &= ~BUFFER_MALLOCD; | |||
354 | } | |||
355 | ||||
356 | return lwan_strbuf_reset(s); | |||
357 | } | |||
358 | ||||
359 | /* This function is quite dangerous, so the prototype is only in lwan-private.h */ | |||
360 | char *lwan_strbuf_extend_unsafe(struct lwan_strbuf *s, size_t by) | |||
361 | { | |||
362 | if (!lwan_strbuf_grow_by(s, by)) | |||
363 | return NULL((void*)0); | |||
364 | ||||
365 | size_t prev_used = s->used; | |||
366 | s->used += by; | |||
367 | ||||
368 | return s->buffer + prev_used; | |||
369 | } | |||
370 | ||||
371 | bool_Bool lwan_strbuf_init_from_file(struct lwan_strbuf *s, const char *path) | |||
372 | { | |||
373 | int fd = open(path, O_RDONLY00 | O_CLOEXEC02000000); | |||
374 | struct stat st; | |||
375 | ||||
376 | if (UNLIKELY(fd < 0)__builtin_expect(((fd < 0)), (0))) | |||
377 | return false0; | |||
378 | ||||
379 | if (UNLIKELY(fstat(fd, &st) < 0)__builtin_expect(((fstat(fd, &st) < 0)), (0))) | |||
380 | goto error; | |||
381 | ||||
382 | size_t min_buf_size; | |||
383 | if (UNLIKELY(__builtin_add_overflow(st.st_size, 1, &min_buf_size))__builtin_expect(((__builtin_add_overflow(st.st_size, 1, & min_buf_size))), (0))) | |||
384 | goto error; | |||
385 | if (UNLIKELY(!lwan_strbuf_init_with_size(s, min_buf_size))__builtin_expect(((!lwan_strbuf_init_with_size(s, min_buf_size ))), (0))) | |||
386 | goto error; | |||
387 | ||||
388 | s->used = (size_t)st.st_size; | |||
389 | ||||
390 | for (char *buffer = s->buffer; st.st_size; ) { | |||
391 | ssize_t n_read = read(fd, buffer, (size_t)st.st_size); | |||
392 | ||||
393 | if (UNLIKELY(n_read < 0)__builtin_expect(((n_read < 0)), (0))) { | |||
394 | if (errno(*__errno_location ()) == EINTR4) | |||
395 | continue; | |||
396 | goto error; | |||
397 | } | |||
398 | ||||
399 | buffer += n_read; | |||
400 | *buffer = '\0'; | |||
401 | st.st_size -= (off_t)n_read; | |||
402 | } | |||
403 | ||||
404 | close(fd); | |||
405 | return true1; | |||
406 | ||||
407 | error: | |||
408 | lwan_strbuf_free(s); | |||
409 | close(fd); | |||
410 | return false0; | |||
411 | } | |||
412 | ||||
413 | struct lwan_strbuf *lwan_strbuf_new_from_file(const char *path) | |||
414 | { | |||
415 | struct lwan_strbuf *strbuf = malloc(sizeof(*strbuf)); | |||
| ||||
416 | ||||
417 | if (!strbuf) | |||
418 | return NULL((void*)0); | |||
419 | ||||
420 | if (lwan_strbuf_init_from_file(strbuf, path)) { | |||
421 | strbuf->flags |= STRBUF_MALLOCD; | |||
422 | return strbuf; | |||
423 | } | |||
424 | ||||
425 | free(strbuf); | |||
426 | return NULL((void*)0); | |||
427 | } |