Bug Summary

File:src/usr.sbin/relayctl/parser.c
Warning:line 222, column 16
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
141 if ((match = match_token(argv[0], table, &res)) == NULL((void *)0)) {
3
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 == NOTOKEN || match->next == NULL((void *)0))
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 not equal to ENDTOKEN
13
Loop condition is true. Entering loop body
175 switch (table[i].type) {
6
Control jumps to 'case PATH:' at line 227
14
Control jumps to 'case RDRID:' at line 215
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
14.1
'word' is not equal to NULL
== NULL((void *)0))
15
Taking false branch
217 break;
218 res->id.id = strtonum(word, 0, UINT_MAX0xffffffffU, &errstr);
219 if (errstr) {
16
Assuming 'errstr' is non-null
17
Taking true branch
220 strlcpy(res->id.name, word,
221 sizeof(res->id.name));
222 res->id.id = EMPTY_ID0xffffffffU;
18
Potential memory leak
223 }
224 t = &table[i];
225 match++;
226 break;
227 case PATH:
228 if (!match
6.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
229 res->path = strdup(word);
10
Memory is allocated
230 match++;
231 t = &table[i];
232 }
233 break;
11
Execution continues on line 174
234 case ENDTOKEN:
235 break;
236 }
237 }
238
239 if (match != 1) {
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}