Bug Summary

File:src/usr.sbin/gpioctl/gpioctl.c
Warning:line 138, column 3
Address of stack memory associated with local variable 'devn' is still referred to by the global variable 'dev' upon returning to the caller. This will be a dangling reference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name gpioctl.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 pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -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/gpioctl/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/gpioctl/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/gpioctl/gpioctl.c
1/* $OpenBSD: gpioctl.c,v 1.17 2015/12/26 20:52:03 mmcc Exp $ */
2/*
3 * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
4 * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/*
20 * Program to control GPIO devices.
21 */
22
23#include <sys/types.h>
24#include <sys/gpio.h>
25#include <sys/ioctl.h>
26#include <sys/limits.h>
27
28#include <err.h>
29#include <errno(*__errno()).h>
30#include <fcntl.h>
31#include <paths.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36
37
38char *dev;
39int devfd = -1;
40int quiet = 0;
41
42void getinfo(void);
43void pinread(int, char *);
44void pinwrite(int, char *, int);
45void pinset(int pin, char *name, int flags, char *alias);
46void unset(int pin, char *name);
47void devattach(char *, int, u_int32_t, u_int32_t);
48void devdetach(char *);
49
50__dead__attribute__((__noreturn__)) void usage(void);
51
52const struct bitstr {
53 unsigned int mask;
54 const char *string;
55} pinflags[] = {
56 { GPIO_PIN_INPUT0x0001, "in" },
57 { GPIO_PIN_OUTPUT0x0002, "out" },
58 { GPIO_PIN_INOUT0x0004, "inout" },
59 { GPIO_PIN_OPENDRAIN0x0008, "od" },
60 { GPIO_PIN_PUSHPULL0x0010, "pp" },
61 { GPIO_PIN_TRISTATE0x0020, "tri" },
62 { GPIO_PIN_PULLUP0x0040, "pu" },
63 { GPIO_PIN_PULLDOWN0x0080, "pd" },
64 { GPIO_PIN_INVIN0x0100, "iin" },
65 { GPIO_PIN_INVOUT0x0200, "iout" },
66 { 0, NULL((void *)0) },
67};
68
69int
70main(int argc, char *argv[])
71{
72 const struct bitstr *bs;
73 long lval;
74 u_int32_t ga_mask = 0, ga_flags = 0;
75 int pin, ch, ga_offset = -1, n, fl = 0, value = 0;
76 const char *errstr;
77 char *ep, *flags, *nam = NULL((void *)0);
78 char devn[32];
79
80 while ((ch = getopt(argc, argv, "q")) != -1)
1
Assuming the condition is false
2
Loop condition is false. Execution continues on line 89
81 switch (ch) {
82 case 'q':
83 quiet = 1;
84 break;
85 default:
86 usage();
87 /* NOTREACHED */
88 }
89 argc -= optind;
90 argv += optind;
91
92 if (argc < 1)
3
Assuming 'argc' is >= 1
4
Taking false branch
93 usage();
94 dev = argv[0];
95
96 if (strncmp(_PATH_DEV"/dev/", dev, sizeof(_PATH_DEV"/dev/") - 1)) {
5
Assuming the condition is true
6
Taking true branch
97 (void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV"/dev/", dev);
98 dev = devn;
99 }
100
101 if ((devfd = open(dev, O_RDWR0x0002)) == -1)
7
Assuming the condition is false
8
Taking false branch
102 err(1, "%s", dev);
103
104 if (argc == 1) {
9
Assuming 'argc' is not equal to 1
10
Taking false branch
105 getinfo();
106 return 0;
107 }
108
109 if (!strcmp(argv[1], "attach")) {
11
Taking true branch
110 char *driver, *offset, *mask;
111
112 if (argc != 5 && argc != 6)
12
Assuming 'argc' is equal to 5
113 usage();
114
115 driver = argv[2];
116 offset = argv[3];
117 mask = argv[4];
118 flags = argc
12.1
'argc' is not equal to 6
== 6 ? argv[5] : NULL((void *)0);
13
'?' condition is false
119
120 ga_offset = strtonum(offset, 0, INT_MAX0x7fffffff, &errstr);
121 if (errstr)
14
Assuming 'errstr' is null
15
Taking false branch
122 errx(1, "offset is %s: %s", errstr, offset);
123
124 lval = strtol(mask, &ep, 0);
125 if (*mask == '\0' || *ep != '\0')
16
Assuming the condition is false
17
Assuming the condition is false
18
Taking false branch
126 errx(1, "invalid mask (not a number)");
127 if ((errno(*__errno()) == ERANGE34 && (lval == LONG_MAX0x7fffffffffffffffL
19
Assuming the condition is false
21
Taking false branch
128 || lval == LONG_MIN(-0x7fffffffffffffffL-1))) || lval > UINT_MAX0xffffffffU)
20
Assuming 'lval' is <= UINT_MAX
129 errx(1, "mask out of range");
130 ga_mask = lval;
131 if (flags
21.1
'flags' is equal to NULL
!= NULL((void *)0)) {
22
Taking false branch
132 lval = strtonum(flags, 0, UINT_MAX0xffffffffU, &errstr);
133 if (errstr)
134 errx(1, "flags is %s: %s", errstr, flags);
135 ga_flags = lval;
136 }
137 devattach(driver, ga_offset, ga_mask, ga_flags);
138 return 0;
23
Address of stack memory associated with local variable 'devn' is still referred to by the global variable 'dev' upon returning to the caller. This will be a dangling reference
139 } else if (!strcmp(argv[1], "detach")) {
140 if (argc != 3)
141 usage();
142 devdetach(argv[2]);
143 } else {
144 char *nm = NULL((void *)0);
145
146 /* expecting a pin number or name */
147 pin = strtonum(argv[1], 0, INT_MAX0x7fffffff, &errstr);
148 if (errstr)
149 nm = argv[1]; /* try named pin */
150 if (argc > 2) {
151 if (!strcmp(argv[2], "set")) {
152 for (n = 3; n < argc; n++) {
153 for (bs = pinflags; bs->string != NULL((void *)0);
154 bs++) {
155 if (!strcmp(argv[n],
156 bs->string)) {
157 fl |= bs->mask;
158 break;
159 }
160 }
161 if (bs->string == NULL((void *)0))
162 nam = argv[n];
163 }
164 pinset(pin, nm, fl, nam);
165 } else if (!strcmp(argv[2], "unset")) {
166 unset(pin, nm);
167 } else {
168 value = strtonum(argv[2], INT_MIN(-0x7fffffff-1), INT_MAX0x7fffffff,
169 &errstr);
170 if (errstr) {
171 if (!strcmp(argv[2], "on"))
172 value = 1;
173 else if (!strcmp(argv[2], "off"))
174 value = 0;
175 else if (!strcmp(argv[2], "toggle"))
176 value = 2;
177 else
178 errx(1, "%s: invalid value",
179 argv[2]);
180 }
181 pinwrite(pin, nm, value);
182 }
183 } else
184 pinread(pin, nm);
185 }
186
187 return (0);
188}
189
190void
191getinfo(void)
192{
193 struct gpio_info info;
194
195 memset(&info, 0, sizeof(info));
196 if (ioctl(devfd, GPIOINFO((unsigned long)0x40000000 | ((sizeof(struct gpio_info) &
0x1fff) << 16) | ((('G')) << 8) | ((0)))
, &info) == -1)
197 err(1, "GPIOINFO");
198
199 if (quiet)
200 return;
201
202 printf("%s: %d pins\n", dev, info.gpio_npins);
203}
204
205void
206pinread(int pin, char *gp_name)
207{
208 struct gpio_pin_op op;
209
210 memset(&op, 0, sizeof(op));
211 if (gp_name != NULL((void *)0))
212 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name));
213 else
214 op.gp_pin = pin;
215
216 if (ioctl(devfd, GPIOPINREAD(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct gpio_pin_op) & 0x1fff) << 16) | ((('G')) <<
8) | ((1)))
, &op) == -1)
217 err(1, "GPIOPINREAD");
218
219 if (quiet)
220 return;
221
222 if (gp_name)
223 printf("pin %s: state %d\n", gp_name, op.gp_value);
224 else
225 printf("pin %d: state %d\n", pin, op.gp_value);
226}
227
228void
229pinwrite(int pin, char *gp_name, int value)
230{
231 struct gpio_pin_op op;
232
233 if (value < 0 || value > 2)
234 errx(1, "%d: invalid value", value);
235
236 memset(&op, 0, sizeof(op));
237 if (gp_name != NULL((void *)0))
238 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name));
239 else
240 op.gp_pin = pin;
241 op.gp_value = (value == 0 ? GPIO_PIN_LOW0x00 : GPIO_PIN_HIGH0x01);
242 if (value < 2) {
243 if (ioctl(devfd, GPIOPINWRITE(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct gpio_pin_op) & 0x1fff) << 16) | ((('G')) <<
8) | ((2)))
, &op) == -1)
244 err(1, "GPIOPINWRITE");
245 } else {
246 if (ioctl(devfd, GPIOPINTOGGLE(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct gpio_pin_op) & 0x1fff) << 16) | ((('G')) <<
8) | ((3)))
, &op) == -1)
247 err(1, "GPIOPINTOGGLE");
248 }
249
250 if (quiet)
251 return;
252
253 if (gp_name)
254 printf("pin %s: state %d -> %d\n", gp_name, op.gp_value,
255 (value < 2 ? value : 1 - op.gp_value));
256 else
257 printf("pin %d: state %d -> %d\n", pin, op.gp_value,
258 (value < 2 ? value : 1 - op.gp_value));
259}
260
261void
262pinset(int pin, char *name, int fl, char *alias)
263{
264 struct gpio_pin_set set;
265 const struct bitstr *bs;
266
267 memset(&set, 0, sizeof(set));
268 if (name != NULL((void *)0))
269 strlcpy(set.gp_name, name, sizeof(set.gp_name));
270 else
271 set.gp_pin = pin;
272 set.gp_flags = fl;
273
274 if (alias != NULL((void *)0))
275 strlcpy(set.gp_name2, alias, sizeof(set.gp_name2));
276
277 if (ioctl(devfd, GPIOPINSET(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct gpio_pin_set) & 0x1fff) << 16) | ((('G')) <<
8) | ((4)))
, &set) == -1)
278 err(1, "GPIOPINSET");
279
280 if (quiet)
281 return;
282
283 if (name != NULL((void *)0))
284 printf("pin %s: caps:", name);
285 else
286 printf("pin %d: caps:", pin);
287 for (bs = pinflags; bs->string != NULL((void *)0); bs++)
288 if (set.gp_caps & bs->mask)
289 printf(" %s", bs->string);
290 printf(", flags:");
291 for (bs = pinflags; bs->string != NULL((void *)0); bs++)
292 if (set.gp_flags & bs->mask)
293 printf(" %s", bs->string);
294 if (fl > 0) {
295 printf(" ->");
296 for (bs = pinflags; bs->string != NULL((void *)0); bs++)
297 if (fl & bs->mask)
298 printf(" %s", bs->string);
299 }
300 printf("\n");
301}
302
303void
304unset(int pin, char *name)
305{
306 struct gpio_pin_set set;
307
308 memset(&set, 0, sizeof(set));
309 if (name != NULL((void *)0))
310 strlcpy(set.gp_name, name, sizeof(set.gp_name));
311 else
312 set.gp_pin = pin;
313
314 if (ioctl(devfd, GPIOPINUNSET(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct gpio_pin_set) & 0x1fff) << 16) | ((('G')) <<
8) | ((5)))
, &set) == -1)
315 err(1, "GPIOPINUNSET");
316}
317
318void
319devattach(char *dvname, int offset, u_int32_t mask, u_int32_t flags)
320{
321 struct gpio_attach attach;
322
323 memset(&attach, 0, sizeof(attach));
324 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
325 attach.ga_offset = offset;
326 attach.ga_mask = mask;
327 attach.ga_flags = flags;
328 if (ioctl(devfd, GPIOATTACH(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct gpio_attach) & 0x1fff) << 16) | ((('G')) <<
8) | ((6)))
, &attach) == -1)
329 err(1, "GPIOATTACH");
330}
331
332void
333devdetach(char *dvname)
334{
335 struct gpio_attach attach;
336
337 memset(&attach, 0, sizeof(attach));
338 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
339 if (ioctl(devfd, GPIODETACH(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct gpio_attach) & 0x1fff) << 16) | ((('G')) <<
8) | ((7)))
, &attach) == -1)
340 err(1, "GPIODETACH");
341}
342void
343usage(void)
344{
345 extern char *__progname;
346
347 fprintf(stderr(&__sF[2]), "usage: %s [-q] device pin [0 | 1 | 2 | "
348 "on | off | toggle]\n", __progname);
349 fprintf(stderr(&__sF[2]), " %s [-q] device pin set [flags] [name]\n",
350 __progname);
351 fprintf(stderr(&__sF[2]), " %s [-q] device pin unset\n", __progname);
352 fprintf(stderr(&__sF[2]), " %s [-q] device attach device offset mask "
353 "[flag]\n", __progname);
354 fprintf(stderr(&__sF[2]), " %s [-q] device detach device\n", __progname);
355
356 exit(1);
357}