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