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