clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name strbuf.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -setup-static-analyzer -mrelocation-model static -mthread-model posix -mframe-pointer=none -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -D LUA_ANSI -D ENABLE_CJSON_GLOBAL -D REDIS_STATIC= -D LUA_USE_MKSTEMP -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir /home/netto/Desktop/redis-6.2.1/deps/lua/src -ferror-limit 19 -fmessage-length 0 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-03-14-133648-8817-1 -x c strbuf.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | #include <stdio.h> |
26 | #include <stdlib.h> |
27 | #include <stdarg.h> |
28 | #include <string.h> |
29 | |
30 | #include "strbuf.h" |
31 | |
32 | static void die(const char *fmt, ...) |
33 | { |
34 | va_list arg; |
35 | |
36 | va_start(arg, fmt); |
37 | vfprintf(stderr, fmt, arg); |
38 | va_end(arg); |
39 | fprintf(stderr, "\n"); |
40 | |
41 | exit(-1); |
42 | } |
43 | |
44 | void strbuf_init(strbuf_t *s, int len) |
45 | { |
46 | int size; |
47 | |
48 | if (len <= 0) |
| |
| |
49 | size = STRBUF_DEFAULT_SIZE; |
50 | else |
51 | size = len + 1; |
52 | |
53 | s->buf = NULL; |
54 | s->size = size; |
55 | s->length = 0; |
56 | s->increment = STRBUF_DEFAULT_INCREMENT; |
57 | s->dynamic = 0; |
58 | s->reallocs = 0; |
59 | s->debug = 0; |
60 | |
61 | s->buf = malloc(size); |
| 6 | | Value assigned to field 'buf' | |
|
62 | if (!s->buf) |
| 7 | | Assuming field 'buf' is null | |
|
| |
63 | die("Out of memory"); |
64 | |
65 | strbuf_ensure_null(s); |
| 9 | | Calling 'strbuf_ensure_null' | |
|
66 | } |
67 | |
68 | strbuf_t *strbuf_new(int len) |
69 | { |
70 | strbuf_t *s; |
71 | |
72 | s = malloc(sizeof(strbuf_t)); |
73 | if (!s) |
| 1 | Assuming 's' is non-null | |
|
| |
74 | die("Out of memory"); |
75 | |
76 | strbuf_init(s, len); |
| |
77 | |
78 | |
79 | s->dynamic = 1; |
80 | |
81 | return s; |
82 | } |
83 | |
84 | void strbuf_set_increment(strbuf_t *s, int increment) |
85 | { |
86 | |
87 | |
88 | if (increment == 0 || increment == -1) |
89 | die("BUG: Invalid string increment"); |
90 | |
91 | s->increment = increment; |
92 | } |
93 | |
94 | static inline void debug_stats(strbuf_t *s) |
95 | { |
96 | if (s->debug) { |
97 | fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %d, size: %d\n", |
98 | (long)s, s->reallocs, s->length, s->size); |
99 | } |
100 | } |
101 | |
102 | |
103 | |
104 | void strbuf_free(strbuf_t *s) |
105 | { |
106 | debug_stats(s); |
107 | |
108 | if (s->buf) { |
109 | free(s->buf); |
110 | s->buf = NULL; |
111 | } |
112 | if (s->dynamic) |
113 | free(s); |
114 | } |
115 | |
116 | char *strbuf_free_to_string(strbuf_t *s, int *len) |
117 | { |
118 | char *buf; |
119 | |
120 | debug_stats(s); |
121 | |
122 | strbuf_ensure_null(s); |
123 | |
124 | buf = s->buf; |
125 | if (len) |
126 | *len = s->length; |
127 | |
128 | if (s->dynamic) |
129 | free(s); |
130 | |
131 | return buf; |
132 | } |
133 | |
134 | static int calculate_new_size(strbuf_t *s, int len) |
135 | { |
136 | int reqsize, newsize; |
137 | |
138 | if (len <= 0) |
139 | die("BUG: Invalid strbuf length requested"); |
140 | |
141 | |
142 | reqsize = len + 1; |
143 | |
144 | |
145 | if (s->size > reqsize) |
146 | return reqsize; |
147 | |
148 | newsize = s->size; |
149 | if (s->increment < 0) { |
150 | |
151 | while (newsize < reqsize) |
152 | newsize *= -s->increment; |
153 | } else { |
154 | |
155 | newsize = ((newsize + s->increment - 1) / s->increment) * s->increment; |
156 | } |
157 | |
158 | return newsize; |
159 | } |
160 | |
161 | |
162 | |
163 | |
164 | void strbuf_resize(strbuf_t *s, int len) |
165 | { |
166 | int newsize; |
167 | |
168 | newsize = calculate_new_size(s, len); |
169 | |
170 | if (s->debug > 1) { |
171 | fprintf(stderr, "strbuf(%lx) resize: %d => %d\n", |
172 | (long)s, s->size, newsize); |
173 | } |
174 | |
175 | s->size = newsize; |
176 | s->buf = realloc(s->buf, s->size); |
177 | if (!s->buf) |
178 | die("Out of memory"); |
179 | s->reallocs++; |
180 | } |
181 | |
182 | void strbuf_append_string(strbuf_t *s, const char *str) |
183 | { |
184 | int space, i; |
185 | |
186 | space = strbuf_empty_length(s); |
187 | |
188 | for (i = 0; str[i]; i++) { |
189 | if (space < 1) { |
190 | strbuf_resize(s, s->length + 1); |
191 | space = strbuf_empty_length(s); |
192 | } |
193 | |
194 | s->buf[s->length] = str[i]; |
195 | s->length++; |
196 | space--; |
197 | } |
198 | } |
199 | |
200 | |
201 | |
202 | void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...) |
203 | { |
204 | va_list arg; |
205 | int fmt_len; |
206 | |
207 | strbuf_ensure_empty_length(s, len); |
208 | |
209 | va_start(arg, fmt); |
210 | fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg); |
211 | va_end(arg); |
212 | |
213 | if (fmt_len < 0) |
214 | die("BUG: Unable to convert number"); |
215 | |
216 | s->length += fmt_len; |
217 | } |
218 | |
219 | |
220 | |
221 | void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...) |
222 | { |
223 | va_list arg; |
224 | int fmt_len, try; |
225 | int empty_len; |
226 | |
227 | |
228 | |
229 | for (try = 0; ; try++) { |
230 | va_start(arg, fmt); |
231 | |
232 | |
233 | |
234 | empty_len = strbuf_empty_length(s); |
235 | |
236 | fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg); |
237 | va_end(arg); |
238 | |
239 | if (fmt_len <= empty_len) |
240 | break; |
241 | if (try > 0) |
242 | die("BUG: length of formatted string changed"); |
243 | |
244 | strbuf_resize(s, s->length + fmt_len); |
245 | } |
246 | |
247 | s->length += fmt_len; |
248 | } |
249 | |
250 | |
251 | |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | #include <stdlib.h> |
26 | #include <stdarg.h> |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | typedef struct { |
35 | char *buf; |
36 | int size; |
37 | int length; |
38 | int increment; |
39 | int dynamic; |
40 | int reallocs; |
41 | int debug; |
42 | } strbuf_t; |
43 | |
44 | #ifndef STRBUF_DEFAULT_SIZE |
45 | #define STRBUF_DEFAULT_SIZE 1023 |
46 | #endif |
47 | #ifndef STRBUF_DEFAULT_INCREMENT |
48 | #define STRBUF_DEFAULT_INCREMENT -2 |
49 | #endif |
50 | |
51 | |
52 | extern strbuf_t *strbuf_new(int len); |
53 | extern void strbuf_init(strbuf_t *s, int len); |
54 | extern void strbuf_set_increment(strbuf_t *s, int increment); |
55 | |
56 | |
57 | extern void strbuf_free(strbuf_t *s); |
58 | extern char *strbuf_free_to_string(strbuf_t *s, int *len); |
59 | |
60 | |
61 | extern void strbuf_resize(strbuf_t *s, int len); |
62 | static int strbuf_empty_length(strbuf_t *s); |
63 | static int strbuf_length(strbuf_t *s); |
64 | static char *strbuf_string(strbuf_t *s, int *len); |
65 | static void strbuf_ensure_empty_length(strbuf_t *s, int len); |
66 | static char *strbuf_empty_ptr(strbuf_t *s); |
67 | static void strbuf_extend_length(strbuf_t *s, int len); |
68 | |
69 | |
70 | extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...); |
71 | extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...); |
72 | static void strbuf_append_mem(strbuf_t *s, const char *c, int len); |
73 | extern void strbuf_append_string(strbuf_t *s, const char *str); |
74 | static void strbuf_append_char(strbuf_t *s, const char c); |
75 | static void strbuf_ensure_null(strbuf_t *s); |
76 | |
77 | |
78 | static inline void strbuf_reset(strbuf_t *s) |
79 | { |
80 | s->length = 0; |
81 | } |
82 | |
83 | static inline int strbuf_allocated(strbuf_t *s) |
84 | { |
85 | return s->buf != NULL; |
86 | } |
87 | |
88 | |
89 | |
90 | static inline int strbuf_empty_length(strbuf_t *s) |
91 | { |
92 | return s->size - s->length - 1; |
93 | } |
94 | |
95 | static inline void strbuf_ensure_empty_length(strbuf_t *s, int len) |
96 | { |
97 | if (len > strbuf_empty_length(s)) |
98 | strbuf_resize(s, s->length + len); |
99 | } |
100 | |
101 | static inline char *strbuf_empty_ptr(strbuf_t *s) |
102 | { |
103 | return s->buf + s->length; |
104 | } |
105 | |
106 | static inline void strbuf_extend_length(strbuf_t *s, int len) |
107 | { |
108 | s->length += len; |
109 | } |
110 | |
111 | static inline int strbuf_length(strbuf_t *s) |
112 | { |
113 | return s->length; |
114 | } |
115 | |
116 | static inline void strbuf_append_char(strbuf_t *s, const char c) |
117 | { |
118 | strbuf_ensure_empty_length(s, 1); |
119 | s->buf[s->length++] = c; |
120 | } |
121 | |
122 | static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c) |
123 | { |
124 | s->buf[s->length++] = c; |
125 | } |
126 | |
127 | static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len) |
128 | { |
129 | strbuf_ensure_empty_length(s, len); |
130 | memcpy(s->buf + s->length, c, len); |
131 | s->length += len; |
132 | } |
133 | |
134 | static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len) |
135 | { |
136 | memcpy(s->buf + s->length, c, len); |
137 | s->length += len; |
138 | } |
139 | |
140 | static inline void strbuf_ensure_null(strbuf_t *s) |
141 | { |
142 | s->buf[s->length] = 0; |
| 10 | | Array access (via field 'buf') results in a null pointer dereference |
|
143 | } |
144 | |
145 | static inline char *strbuf_string(strbuf_t *s, int *len) |
146 | { |
147 | if (len) |
148 | *len = s->length; |
149 | |
150 | return s->buf; |
151 | } |
152 | |
153 | |
154 | |