Bug Summary

File:util/str2argv.c
Location:line 66, column 8
Description:Null pointer argument in call to string length function

Annotated Source Code

1/*
2 * Copyright (c) 2010, 2011, 2012 Ryan Flannery <ryan.flannery@gmail.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "str2argv.h"
18
19/* initialize empty argc/argv struct */
20void
21argv_init(int *argc, char ***argv)
22{
23 if ((*argv = calloc(ARGV_MAX_ENTRIES255, sizeof(char*))) == NULL((void *)0))
24 err(1, "argv_init: argv calloc fail");
25
26 if (((*argv)[0] = calloc(ARGV_MAX_TOKEN_LEN255, sizeof(char))) == NULL((void *)0))
27 err(1, "argv_init: argv[i] calloc fail");
28
29 bzero((*argv)[0], ARGV_MAX_TOKEN_LEN255 * sizeof(char));
30 *argc = 0;
31}
32
33/* free all memory in an arc/argv */
34void
35argv_free(int *argc, char ***argv)
36{
37 int i;
38
39 for (i = 0; i <= *argc; i++)
40 free((*argv)[i]);
41
42 free(*argv);
43 *argc = 0;
44}
45
46/* add a character to the end of the current entry in an argc/argv */
47void
48argv_addch(int argc, char **argv, int c)
49{
50 int n;
51
52 n = strlen(argv[argc]);
53 if (n == ARGV_MAX_TOKEN_LEN255 - 1)
54 errx(1, "argv_addch: reached max token length (%d)", ARGV_MAX_TOKEN_LEN255);
55
56 argv[argc][n] = c;
57}
58
59/* complete the current entry in the argc/argv and setup the next one */
60void
61argv_finish_token(int *argc, char ***argv)
62{
63 if (*argc == ARGV_MAX_ENTRIES255 - 1)
16
Taking false branch
64 errx(1, "argv_finish_token: reached max argv entries(%d)", ARGV_MAX_ENTRIES255);
65
66 if (strlen((*argv)[*argc]) == 0)
17
Null pointer argument in call to string length function
67 return;
68
69 *argc = *argc + 1;
70 if (((*argv)[*argc] = calloc(ARGV_MAX_TOKEN_LEN255, sizeof(char))) == NULL((void *)0))
71 err(1, "argv_finish_token: failed to calloc argv[i]");
72
73 bzero((*argv)[*argc], ARGV_MAX_TOKEN_LEN255 * sizeof(char));
74}
75
76/*
77 * Main parser used for converting a string (str) to an argc/argv style
78 * parameter list. This handles escape sequences and quoting. Possibly
79 * correctly. :D
80 * The argc/argv parameters passed are over-written. After they have been
81 * built by this function, the caller should use argv_free() on them to
82 * free() all associated memory.
83 * If the parsing goes correctly, 0 is returned. Otherwise, 1 is returned
84 * and the errmsg parameter is set to some appropriate error message and
85 * both argc/argv are set to 0/NULL.
86 */
87int
88str2argv(char *str, int *argc, char ***argv, const char **errmsg)
89{
90 bool_Bool in_token;
91 bool_Bool in_container;
92 bool_Bool escaped;
93 char container_start;
94 char c;
95 int len;
96 int i;
97
98 const char *ERRORS[2] = {
99 "Unmatched quotes",
100 "Unused/Dangling escape sequence"
101 };
102 *errmsg = NULL((void *)0);
103
104 container_start = 0;
105 in_token = false0;
106 in_container = false0;
107 escaped = false0;
108
109 len = strlen(str);
110
111 argv_init(argc, argv);
112 for (i = 0; i < len; i++) {
1
Assuming 'i' is < 'len'
2
Loop condition is true. Entering loop body
6
Assuming 'i' is < 'len'
7
Loop condition is true. Entering loop body
13
Assuming 'i' is >= 'len'
14
Loop condition is false. Execution continues on line 203
113 c = str[i];
114
115 switch (c) {
3
Control jumps to the 'default' case at line 193
8
Control jumps to 'case 10:' at line 119
116 /* handle whitespace */
117 case ' ':
118 case '\t':
119 case '\n':
120 if (!in_token)
9
Taking false branch
121 continue;
122
123 if (in_container) {
10
Taking false branch
124 argv_addch(*argc, *argv, c);
125 continue;
126 }
127
128 if (escaped) {
11
Taking false branch
129 escaped = false0;
130 argv_addch(*argc, *argv, c);
131 continue;
132 }
133
134 /* if reached here, we're at end of token */
135 in_token = false0;
136 argv_finish_token(argc, argv);
137 break;
12
Execution continues on line 112
138
139 /* handle quotes */
140 case '\'':
141 case '\"':
142
143 if (escaped) {
144 argv_addch(*argc, *argv, c);
145 escaped = false0;
146 continue;
147 }
148
149 if (!in_token) {
150 in_token = true1;
151 in_container = true1;
152 container_start = c;
153 continue;
154 }
155
156 if (in_token && !in_container) {
157 in_container = true1;
158 container_start = c;
159 continue;
160 }
161
162 if (in_container) {
163 if (c == container_start) {
164 in_container = false0;
165 in_token = false0;
166 argv_finish_token(argc, argv);
167 continue;
168 } else {
169 argv_addch(*argc, *argv, c);
170 continue;
171 }
172 }
173
174 *errmsg = ERRORS[0];
175 argv_free(argc, argv);
176 return 1;
177
178 case '\\':
179 if (in_container && str[i+1] != container_start) {
180 argv_addch(*argc, *argv, c);
181 continue;
182 }
183
184 if (escaped) {
185 escaped = false0;
186 argv_addch(*argc, *argv, c);
187 continue;
188 }
189
190 escaped = true1;
191 break;
192
193 default:
194 if (!in_token)
4
Taking true branch
195 in_token = true1;
196
197 if (escaped)
5
Taking false branch
198 escaped = false0;
199
200 argv_addch(*argc, *argv, c);
201 }
202 }
203 argv_finish_token(argc, argv);
15
Calling 'argv_finish_token'
204
205 if (in_container) {
206 argv_free(argc, argv);
207 *errmsg = ERRORS[0];
208 return 1;
209 }
210
211 if (escaped) {
212 argv_free(argc, argv);
213 *errmsg = ERRORS[1];
214 return 1;
215 }
216
217 (*argv)[*argc] = NULL((void *)0);/*XXX*/
218
219 return 0;
220}
221
222char *
223argv2str(int argc, char *argv[])
224{
225 char *result;
226 int len;
227 int off;
228 int i;
229
230 /* handle empty case */
231 if (0 >= argc)
232 return NULL((void *)0);
233
234 /* determine length of resulting string */
235 len = 0;
236 for (i = 0; i < argc; i++) {
237 len += strlen(argv[i]) + 1;
238 if (strstr(argv[i], " ") != NULL((void *)0))
239 len += 2;
240 }
241
242 /* allocate result */
243 if ((result = calloc(len, sizeof(char))) == NULL((void *)0))
244 err(1, "argv2str: calloc failed");
245 bzero(result, len);
246
247 /* build result */
248 off = 0;
249 for (i = 0; i < argc; i++) {
250 if (strstr(argv[i], " ") == NULL((void *)0))
251 off += snprintf(result + off, len, "%s ", argv[i]);
252 else
253 off += snprintf(result + off, len, "\'%s\' ", argv[i]);
254 }
255
256 return result;
257}