Bug Summary

File:src/usr.sbin/relayctl/parser.c
Warning:line 230, column 5
Potential memory leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name parser.c -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 pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/relayctl/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/usr.sbin/relayctl -I /usr/src/usr.sbin/relayctl/../relayd -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/relayctl/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/relayctl/parser.c
1/* $OpenBSD: parser.c,v 1.28 2018/05/11 20:33:54 reyk Exp $ */
2
3/*
4 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
5 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/types.h>
22
23#include <limits.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "relayd.h"
29#include "parser.h"
30
31enum token_type {
32 NOTOKEN,
33 ENDTOKEN,
34 HOSTID,
35 TABLEID,
36 RDRID,
37 KEYWORD,
38 PATH
39};
40
41struct token {
42 enum token_type type;
43 const char *keyword;
44 int value;
45 const struct token *next;
46};
47
48static const struct token t_main[];
49static const struct token t_show[];
50static const struct token t_rdr[];
51static const struct token t_table[];
52static const struct token t_host[];
53static const struct token t_rdr_id[];
54static const struct token t_table_id[];
55static const struct token t_host_id[];
56static const struct token t_log[];
57static const struct token t_load[];
58
59static const struct token t_main[] = {
60 {KEYWORD, "monitor", MONITOR, NULL((void *)0)},
61 {KEYWORD, "show", NONE, t_show},
62 {KEYWORD, "load", LOAD, t_load},
63 {KEYWORD, "poll", POLL, NULL((void *)0)},
64 {KEYWORD, "reload", RELOAD, NULL((void *)0)},
65 {KEYWORD, "stop", SHUTDOWN, NULL((void *)0)},
66 {KEYWORD, "redirect", NONE, t_rdr},
67 {KEYWORD, "table", NONE, t_table},
68 {KEYWORD, "host", NONE, t_host},
69 {KEYWORD, "log", NONE, t_log},
70 {ENDTOKEN, "", NONE, NULL((void *)0)}
71};
72
73static const struct token t_show[] = {
74 {KEYWORD, "summary", SHOW_SUM, NULL((void *)0)},
75 {KEYWORD, "hosts", SHOW_HOSTS, NULL((void *)0)},
76 {KEYWORD, "redirects", SHOW_RDRS, NULL((void *)0)},
77 {KEYWORD, "relays", SHOW_RELAYS, NULL((void *)0)},
78 {KEYWORD, "routers", SHOW_ROUTERS, NULL((void *)0)},
79 {KEYWORD, "sessions", SHOW_SESSIONS, NULL((void *)0)},
80 {ENDTOKEN, "", NONE, NULL((void *)0)}
81};
82
83static const struct token t_rdr[] = {
84 {KEYWORD, "disable", RDR_DISABLE, t_rdr_id},
85 {KEYWORD, "enable", RDR_ENABLE, t_rdr_id},
86 {ENDTOKEN, "", NONE, NULL((void *)0)}
87};
88
89static const struct token t_table[] = {
90 {KEYWORD, "disable", TABLE_DISABLE, t_table_id},
91 {KEYWORD, "enable", TABLE_ENABLE, t_table_id},
92 {ENDTOKEN, "", NONE, NULL((void *)0)}
93};
94
95static const struct token t_host[] = {
96 {KEYWORD, "disable", HOST_DISABLE, t_host_id},
97 {KEYWORD, "enable", HOST_ENABLE, t_host_id},
98 {ENDTOKEN, "", NONE, NULL((void *)0)}
99};
100
101static const struct token t_rdr_id[] = {
102 {RDRID, "", NONE, NULL((void *)0)},
103 {ENDTOKEN, "", NONE, NULL((void *)0)}
104};
105
106static const struct token t_table_id[] = {
107 {TABLEID, "", NONE, NULL((void *)0)},
108 {ENDTOKEN, "", NONE, NULL((void *)0)}
109};
110
111static const struct token t_host_id[] = {
112 {HOSTID, "", NONE, NULL((void *)0)},
113 {ENDTOKEN, "", NONE, NULL((void *)0)}
114};
115
116static const struct token t_log[] = {
117 {KEYWORD, "verbose", LOG_VERBOSE, NULL((void *)0)},
118 {KEYWORD, "brief", LOG_BRIEF, NULL((void *)0)},
119 {ENDTOKEN, "", NONE, NULL((void *)0)}
120};
121
122static const struct token t_load[] = {
123 {PATH, "", NONE, NULL((void *)0)},
124 {ENDTOKEN, "", NONE, NULL((void *)0)}
125};
126
127static const struct token *match_token(const char *, const struct token *,
128 struct parse_result *);
129static void show_valid_args(const struct token *);
130
131struct parse_result *
132parse(int argc, char *argv[])
133{
134 static struct parse_result res;
135 const struct token *table = t_main;
136 const struct token *match;
137
138 bzero(&res, sizeof(res));
139
140 while (argc >= 0) {
1
Assuming 'argc' is >= 0
2
Loop condition is true. Entering loop body
19
Assuming 'argc' is >= 0
20
Loop condition is true. Entering loop body
141 if ((match = match_token(argv[0], table, &res)) == NULL((void *)0)) {
3
Calling 'match_token'
15
Returned allocated memory
16
Taking false branch
21
Calling 'match_token'
142 fprintf(stderr(&__sF[2]), "valid commands/args:\n");
143 show_valid_args(table);
144 return (NULL((void *)0));
145 }
146
147 argc--;
148 argv++;
149
150 if (match->type
16.1
Field 'type' is not equal to NOTOKEN
== NOTOKEN || match->next == NULL((void *)0))
17
Assuming field 'next' is not equal to NULL
18
Taking false branch
151 break;
152
153 table = match->next;
154 }
155
156 if (argc > 0) {
157 fprintf(stderr(&__sF[2]), "superfluous argument: %s\n", argv[0]);
158 return (NULL((void *)0));
159 }
160
161 return (&res);
162}
163
164static const struct token *
165match_token(const char *word, const struct token *table,
166 struct parse_result *res)
167{
168 u_int i, match;
169 const struct token *t = NULL((void *)0);
170 const char *errstr;
171
172 match = 0;
173
174 for (i = 0; table[i].type != ENDTOKEN; i++) {
4
Assuming field 'type' is not equal to ENDTOKEN
5
Loop condition is true. Entering loop body
12
Assuming field 'type' is equal to ENDTOKEN
13
Loop condition is false. Execution continues on line 239
22
Assuming field 'type' is not equal to ENDTOKEN
23
Loop condition is true. Entering loop body
175 switch (table[i].type) {
6
Control jumps to 'case PATH:' at line 227
24
Control jumps to 'case PATH:' at line 227
176 case NOTOKEN:
177 if (word == NULL((void *)0) || strlen(word) == 0) {
178 match++;
179 t = &table[i];
180 }
181 break;
182 case KEYWORD:
183 if (word != NULL((void *)0) && strncmp(word, table[i].keyword,
184 strlen(word)) == 0) {
185 match++;
186 t = &table[i];
187 if (t->value)
188 res->action = t->value;
189 }
190 break;
191 case HOSTID:
192 if (word == NULL((void *)0))
193 break;
194 res->id.id = strtonum(word, 0, UINT_MAX0xffffffffU, &errstr);
195 if (errstr) {
196 strlcpy(res->id.name, word,
197 sizeof(res->id.name));
198 res->id.id = EMPTY_ID0xffffffffU;
199 }
200 t = &table[i];
201 match++;
202 break;
203 case TABLEID:
204 if (word == NULL((void *)0))
205 break;
206 res->id.id = strtonum(word, 0, UINT_MAX0xffffffffU, &errstr);
207 if (errstr) {
208 strlcpy(res->id.name, word,
209 sizeof(res->id.name));
210 res->id.id = EMPTY_ID0xffffffffU;
211 }
212 t = &table[i];
213 match++;
214 break;
215 case RDRID:
216 if (word == NULL((void *)0))
217 break;
218 res->id.id = strtonum(word, 0, UINT_MAX0xffffffffU, &errstr);
219 if (errstr) {
220 strlcpy(res->id.name, word,
221 sizeof(res->id.name));
222 res->id.id = EMPTY_ID0xffffffffU;
223 }
224 t = &table[i];
225 match++;
226 break;
227 case PATH:
228 if (!match
6.1
'match' is 0
24.1
'match' is 0
&& word != NULL((void *)0) && strlen(word) > 0) {
7
Assuming 'word' is not equal to NULL
8
Assuming the condition is true
9
Taking true branch
25
Assuming 'word' is not equal to NULL
26
Assuming the condition is true
27
Taking true branch
229 res->path = strdup(word);
10
Memory is allocated
230 match++;
28
Potential memory leak
231 t = &table[i];
232 }
233 break;
11
Execution continues on line 174
234 case ENDTOKEN:
235 break;
236 }
237 }
238
239 if (match
13.1
'match' is equal to 1
!= 1) {
14
Taking false branch
240 if (word == NULL((void *)0))
241 fprintf(stderr(&__sF[2]), "missing argument:\n");
242 else if (match > 1)
243 fprintf(stderr(&__sF[2]), "ambiguous argument: %s\n", word);
244 else if (match < 1)
245 fprintf(stderr(&__sF[2]), "unknown argument: %s\n", word);
246 return (NULL((void *)0));
247 }
248
249 return (t);
250}
251
252static void
253show_valid_args(const struct token *table)
254{
255 int i;
256
257 for (i = 0; table[i].type != ENDTOKEN; i++) {
258 switch (table[i].type) {
259 case NOTOKEN:
260 fprintf(stderr(&__sF[2]), " <cr>\n");
261 break;
262 case KEYWORD:
263 fprintf(stderr(&__sF[2]), " %s\n", table[i].keyword);
264 break;
265 case RDRID:
266 fprintf(stderr(&__sF[2]), " <redirectid>\n");
267 break;
268 case TABLEID:
269 fprintf(stderr(&__sF[2]), " <tableid>\n");
270 break;
271 case HOSTID:
272 fprintf(stderr(&__sF[2]), " <hostid>\n");
273 break;
274 case PATH:
275 fprintf(stderr(&__sF[2]), " <path>\n");
276 break;
277 case ENDTOKEN:
278 break;
279 }
280 }
281}