File: | lib/lwan-strbuf.c |
Warning: | line 319, column 22 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * lwan - simple 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 <limits.h> | |||
23 | #include <stdarg.h> | |||
24 | #include <stdlib.h> | |||
25 | #include <string.h> | |||
26 | ||||
27 | #include "lwan-private.h" | |||
28 | ||||
29 | static const unsigned int BUFFER_MALLOCD = 1 << 0; | |||
30 | static const unsigned int STRBUF_MALLOCD = 1 << 1; | |||
31 | static const unsigned int BUFFER_FIXED = 1 << 2; | |||
32 | ||||
33 | static inline size_t align_size(size_t unaligned_size) | |||
34 | { | |||
35 | const size_t aligned_size = lwan_nextpow2(unaligned_size); | |||
36 | ||||
37 | if (UNLIKELY(unaligned_size >= aligned_size)__builtin_expect(((unaligned_size >= aligned_size)), (0))) | |||
38 | return 0; | |||
39 | ||||
40 | return aligned_size; | |||
41 | } | |||
42 | ||||
43 | static bool_Bool grow_buffer_if_needed(struct lwan_strbuf *s, size_t size) | |||
44 | { | |||
45 | if (s->flags & BUFFER_FIXED) | |||
46 | return size < s->capacity; | |||
47 | ||||
48 | if (!(s->flags & BUFFER_MALLOCD)) { | |||
49 | 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 ; })); | |||
50 | if (UNLIKELY(!aligned_size)__builtin_expect(((!aligned_size)), (0))) | |||
51 | return false0; | |||
52 | ||||
53 | char *buffer = malloc(aligned_size); | |||
54 | if (UNLIKELY(!buffer)__builtin_expect(((!buffer)), (0))) | |||
55 | return false0; | |||
56 | ||||
57 | memcpy(buffer, s->buffer, s->used); | |||
58 | buffer[s->used + 1] = '\0'; | |||
59 | ||||
60 | s->flags |= BUFFER_MALLOCD; | |||
61 | s->buffer = buffer; | |||
62 | s->capacity = aligned_size; | |||
63 | ||||
64 | return true1; | |||
65 | } | |||
66 | ||||
67 | if (UNLIKELY(s->capacity < size)__builtin_expect(((s->capacity < size)), (0))) { | |||
68 | char *buffer; | |||
69 | const size_t aligned_size = align_size(size + 1); | |||
70 | ||||
71 | if (UNLIKELY(!aligned_size)__builtin_expect(((!aligned_size)), (0))) | |||
72 | return false0; | |||
73 | ||||
74 | if (s->used == 0) { | |||
75 | /* Avoid memcpy() inside realloc() if we were not using the | |||
76 | * allocated buffer at this point. */ | |||
77 | buffer = malloc(aligned_size); | |||
78 | ||||
79 | if (UNLIKELY(!buffer)__builtin_expect(((!buffer)), (0))) | |||
80 | return false0; | |||
81 | ||||
82 | free(s->buffer); | |||
83 | buffer[0] = '\0'; | |||
84 | } else { | |||
85 | buffer = realloc(s->buffer, aligned_size); | |||
86 | ||||
87 | if (UNLIKELY(!buffer)__builtin_expect(((!buffer)), (0))) | |||
88 | return false0; | |||
89 | } | |||
90 | ||||
91 | s->buffer = buffer; | |||
92 | s->capacity = aligned_size; | |||
93 | } | |||
94 | ||||
95 | return true1; | |||
96 | } | |||
97 | ||||
98 | bool_Bool lwan_strbuf_init_with_size(struct lwan_strbuf *s, size_t size) | |||
99 | { | |||
100 | if (UNLIKELY(!s)__builtin_expect(((!s)), (0))) | |||
101 | return false0; | |||
102 | ||||
103 | *s = LWAN_STRBUF_STATIC_INIT(struct lwan_strbuf) { .buffer = "" }; | |||
104 | ||||
105 | if (size) { | |||
106 | if (UNLIKELY(!grow_buffer_if_needed(s, size))__builtin_expect(((!grow_buffer_if_needed(s, size))), (0))) | |||
107 | return false0; | |||
108 | ||||
109 | s->buffer[0] = '\0'; | |||
110 | } | |||
111 | ||||
112 | return true1; | |||
113 | } | |||
114 | ||||
115 | bool_Bool lwan_strbuf_init_with_fixed_buffer(struct lwan_strbuf *s, | |||
116 | void *buffer, | |||
117 | size_t size) | |||
118 | { | |||
119 | if (UNLIKELY(!s)__builtin_expect(((!s)), (0))) | |||
120 | return false0; | |||
121 | ||||
122 | *s = (struct lwan_strbuf) { | |||
123 | .capacity = size, | |||
124 | .used = 0, | |||
125 | .buffer = buffer, | |||
126 | .flags = BUFFER_FIXED, | |||
127 | }; | |||
128 | ||||
129 | return true1; | |||
130 | } | |||
131 | ||||
132 | ALWAYS_INLINEinline __attribute__((always_inline)) bool_Bool lwan_strbuf_init(struct lwan_strbuf *s) | |||
133 | { | |||
134 | return lwan_strbuf_init_with_size(s, 0); | |||
135 | } | |||
136 | ||||
137 | struct lwan_strbuf *lwan_strbuf_new_with_size(size_t size) | |||
138 | { | |||
139 | struct lwan_strbuf *s = malloc(sizeof(*s)); | |||
140 | ||||
141 | if (UNLIKELY(!lwan_strbuf_init_with_size(s, size))__builtin_expect(((!lwan_strbuf_init_with_size(s, size))), (0 ))) { | |||
142 | free(s); | |||
143 | ||||
144 | return NULL((void*)0); | |||
145 | } | |||
146 | ||||
147 | s->flags |= STRBUF_MALLOCD; | |||
148 | ||||
149 | return s; | |||
150 | } | |||
151 | ||||
152 | struct lwan_strbuf *lwan_strbuf_new_with_fixed_buffer(size_t size) | |||
153 | { | |||
154 | struct lwan_strbuf *s = malloc(sizeof(*s) + size + 1); | |||
155 | ||||
156 | 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))) { | |||
157 | free(s); | |||
158 | ||||
159 | return NULL((void*)0); | |||
160 | } | |||
161 | ||||
162 | s->flags |= STRBUF_MALLOCD; | |||
163 | ||||
164 | return s; | |||
165 | } | |||
166 | ||||
167 | ALWAYS_INLINEinline __attribute__((always_inline)) struct lwan_strbuf *lwan_strbuf_new(void) | |||
168 | { | |||
169 | return lwan_strbuf_new_with_size(0); | |||
170 | } | |||
171 | ||||
172 | ALWAYS_INLINEinline __attribute__((always_inline)) struct lwan_strbuf *lwan_strbuf_new_static(const char *str, | |||
173 | size_t size) | |||
174 | { | |||
175 | struct lwan_strbuf *s = malloc(sizeof(*s)); | |||
176 | ||||
177 | if (UNLIKELY(!s)__builtin_expect(((!s)), (0))) | |||
178 | return NULL((void*)0); | |||
179 | ||||
180 | *s = (struct lwan_strbuf) { | |||
181 | .flags = STRBUF_MALLOCD, | |||
182 | .buffer = (char *)str, | |||
183 | .used = size, | |||
184 | .capacity = size, | |||
185 | }; | |||
186 | ||||
187 | return s; | |||
188 | } | |||
189 | ||||
190 | void lwan_strbuf_free(struct lwan_strbuf *s) | |||
191 | { | |||
192 | if (UNLIKELY(!s)__builtin_expect(((!s)), (0))) | |||
193 | return; | |||
194 | if (s->flags & BUFFER_MALLOCD) { | |||
195 | 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" , 195, __extension__ __PRETTY_FUNCTION__); })); | |||
196 | free(s->buffer); | |||
197 | } | |||
198 | if (s->flags & STRBUF_MALLOCD) | |||
199 | free(s); | |||
200 | } | |||
201 | ||||
202 | bool_Bool lwan_strbuf_append_char(struct lwan_strbuf *s, const char c) | |||
203 | { | |||
204 | if (UNLIKELY(!grow_buffer_if_needed(s, s->used + 2))__builtin_expect(((!grow_buffer_if_needed(s, s->used + 2)) ), (0))) | |||
205 | return false0; | |||
206 | ||||
207 | s->buffer[s->used++] = c; | |||
208 | s->buffer[s->used] = '\0'; | |||
209 | ||||
210 | return true1; | |||
211 | } | |||
212 | ||||
213 | bool_Bool lwan_strbuf_append_str(struct lwan_strbuf *s1, const char *s2, size_t sz) | |||
214 | { | |||
215 | if (UNLIKELY(!grow_buffer_if_needed(s1, s1->used + sz + 2))__builtin_expect(((!grow_buffer_if_needed(s1, s1->used + sz + 2))), (0))) | |||
216 | return false0; | |||
217 | ||||
218 | memcpy(s1->buffer + s1->used, s2, sz); | |||
219 | s1->used += sz; | |||
220 | s1->buffer[s1->used] = '\0'; | |||
221 | ||||
222 | return true1; | |||
223 | } | |||
224 | ||||
225 | bool_Bool lwan_strbuf_set_static(struct lwan_strbuf *s1, const char *s2, size_t sz) | |||
226 | { | |||
227 | if (s1->flags & BUFFER_MALLOCD) | |||
228 | free(s1->buffer); | |||
229 | ||||
230 | s1->buffer = (char *)s2; | |||
231 | s1->used = s1->capacity = sz; | |||
232 | s1->flags &= ~(BUFFER_MALLOCD | BUFFER_FIXED); | |||
233 | ||||
234 | return true1; | |||
235 | } | |||
236 | ||||
237 | bool_Bool lwan_strbuf_set(struct lwan_strbuf *s1, const char *s2, size_t sz) | |||
238 | { | |||
239 | if (UNLIKELY(!grow_buffer_if_needed(s1, sz + 1))__builtin_expect(((!grow_buffer_if_needed(s1, sz + 1))), (0))) | |||
240 | return false0; | |||
241 | ||||
242 | memcpy(s1->buffer, s2, sz); | |||
243 | s1->used = sz; | |||
244 | s1->buffer[sz] = '\0'; | |||
245 | ||||
246 | return true1; | |||
247 | } | |||
248 | ||||
249 | static ALWAYS_INLINEinline __attribute__((always_inline)) bool_Bool | |||
250 | internal_printf(struct lwan_strbuf *s1, | |||
251 | bool_Bool (*save_str)(struct lwan_strbuf *, const char *, size_t), | |||
252 | const char *fmt, | |||
253 | va_list values) | |||
254 | { | |||
255 | char *s2; | |||
256 | int len; | |||
257 | ||||
258 | if (UNLIKELY((len = vasprintf(&s2, fmt, values)) < 0)__builtin_expect((((len = vasprintf(&s2, fmt, values)) < 0)), (0))) | |||
259 | return false0; | |||
260 | ||||
261 | bool_Bool success = save_str(s1, s2, (size_t)len); | |||
262 | free(s2); | |||
263 | ||||
264 | return success; | |||
265 | } | |||
266 | ||||
267 | bool_Bool lwan_strbuf_vprintf(struct lwan_strbuf *s, const char *fmt, va_list ap) | |||
268 | { | |||
269 | return internal_printf(s, lwan_strbuf_set, fmt, ap); | |||
270 | } | |||
271 | ||||
272 | bool_Bool lwan_strbuf_printf(struct lwan_strbuf *s, const char *fmt, ...) | |||
273 | { | |||
274 | bool_Bool could_printf; | |||
275 | va_list values; | |||
276 | ||||
277 | va_start(values, fmt)__builtin_va_start(values, fmt); | |||
278 | could_printf = lwan_strbuf_vprintf(s, fmt, values); | |||
279 | va_end(values)__builtin_va_end(values); | |||
280 | ||||
281 | return could_printf; | |||
282 | } | |||
283 | ||||
284 | bool_Bool lwan_strbuf_append_vprintf(struct lwan_strbuf *s, const char *fmt, va_list ap) | |||
285 | { | |||
286 | return internal_printf(s, lwan_strbuf_append_str, fmt, ap); | |||
287 | } | |||
288 | ||||
289 | bool_Bool lwan_strbuf_append_printf(struct lwan_strbuf *s, const char *fmt, ...) | |||
290 | { | |||
291 | bool_Bool could_printf; | |||
292 | va_list values; | |||
293 | ||||
294 | va_start(values, fmt)__builtin_va_start(values, fmt); | |||
295 | could_printf = lwan_strbuf_append_vprintf(s, fmt, values); | |||
296 | va_end(values)__builtin_va_end(values); | |||
297 | ||||
298 | return could_printf; | |||
299 | } | |||
300 | ||||
301 | bool_Bool lwan_strbuf_grow_to(struct lwan_strbuf *s, size_t new_size) | |||
302 | { | |||
303 | return grow_buffer_if_needed(s, new_size + 1); | |||
304 | } | |||
305 | ||||
306 | bool_Bool lwan_strbuf_grow_by(struct lwan_strbuf *s, size_t offset) | |||
307 | { | |||
308 | size_t new_size; | |||
309 | ||||
310 | if (__builtin_add_overflow(offset, s->used, &new_size)) | |||
311 | return false0; | |||
312 | ||||
313 | return lwan_strbuf_grow_to(s, new_size); | |||
314 | } | |||
315 | ||||
316 | void lwan_strbuf_reset(struct lwan_strbuf *s) | |||
317 | { | |||
318 | if (s->flags & BUFFER_MALLOCD) { | |||
319 | s->buffer[0] = '\0'; | |||
| ||||
320 | } else { | |||
321 | s->buffer = ""; | |||
322 | s->capacity = 0; | |||
323 | } | |||
324 | ||||
325 | s->used = 0; | |||
326 | } | |||
327 | ||||
328 | void lwan_strbuf_reset_trim(struct lwan_strbuf *s, size_t trim_thresh) | |||
329 | { | |||
330 | if (s->flags & BUFFER_MALLOCD && s->capacity > trim_thresh) { | |||
| ||||
331 | free(s->buffer); | |||
332 | s->flags &= ~BUFFER_MALLOCD; | |||
333 | } | |||
334 | ||||
335 | return lwan_strbuf_reset(s); | |||
336 | } | |||
337 | ||||
338 | /* This function is quite dangerous, so the prototype is only in lwan-private.h */ | |||
339 | char *lwan_strbuf_extend_unsafe(struct lwan_strbuf *s, size_t by) | |||
340 | { | |||
341 | if (!lwan_strbuf_grow_by(s, by)) | |||
342 | return NULL((void*)0); | |||
343 | ||||
344 | size_t prev_used = s->used; | |||
345 | s->used += by; | |||
346 | ||||
347 | return s->buffer + prev_used; | |||
348 | } |