Bug Summary

File:.build-ci/../nvme-models.c
Warning:line 219, column 9
Read function called when stream is in EOF state. Function has no effect

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nvme-models.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 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -std=gnu99 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-06-24-175442-590-1 -x c ../nvme-models.c
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2#include <errno(*__errno_location ()).h>
3#include <fcntl.h>
4#include <stdbool.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9
10#include <sys/stat.h>
11#include <sys/types.h>
12#include "nvme-models.h"
13#include "nvme.h"
14
15static char *_fmt1 = "/sys/class/nvme/nvme%d/device/subsystem_vendor";
16static char *_fmt2 = "/sys/class/nvme/nvme%d/device/subsystem_device";
17static char *_fmt3 = "/sys/class/nvme/nvme%d/device/vendor";
18static char *_fmt4 = "/sys/class/nvme/nvme%d/device/device";
19static char *_fmt5 = "/sys/class/nvme/nvme%d/device/class";
20
21#define LINE_BUF_SIZE1024 1024
22
23static char fmt1[78];
24static char fmt2[78];
25static char fmt3[78];
26static char fmt4[78];
27static char fmt5[78];
28
29static char *device_top;
30static char *device_mid;
31static char *device_final;
32static char *class_top;
33static char *class_mid;
34static char *class_final;
35
36
37
38static void free_all(void)
39{
40 free(device_top);
41 device_top = NULL((void*)0);
42 free(device_mid);
43 device_mid = NULL((void*)0);
44 free(device_final);
45 device_final = NULL((void*)0);
46 free(class_top);
47 class_top = NULL((void*)0);
48 free(class_mid);
49 class_mid = NULL((void*)0);
50 free(class_final);
51 class_final = NULL((void*)0);
52}
53
54static char *find_data(char *data)
55{
56 while (*data != '\0') {
57 if (*data >= '0' && *data <= '9')
58 return data;
59 data++;
60 }
61 return NULL((void*)0);
62}
63
64static char *locate_info(char *data, bool_Bool is_inner, bool_Bool is_class)
65{
66 char *orig = data;
67 char *locate;
68 if (!data)
69 return orig;
70
71 locate = find_data(data);
72 if (!locate)
73 return orig;
74 if (is_class)
75 return locate + 4;
76 if (!is_inner)
77 /* 4 to get over the number, 2 for spaces */
78 return locate + 4 + 2;
79
80 /* Inner data, has "sub_ven(space)sub_dev(space)(space)string */
81 return locate + 4 + 1 + 4 + 2;
82}
83
84static void format_and_print(char *save)
85{
86
87 if (!class_mid) {
88 if (device_final)
89 snprintf(save, LINE_BUF_SIZE1024, "%s %s %s",
90 locate_info(device_top, false0, false0),
91 locate_info(device_mid, false0, false0),
92 locate_info(device_final, true1, false0));
93 else
94 snprintf(save, LINE_BUF_SIZE1024, "%s %s",
95 locate_info(device_top, false0, false0),
96 locate_info(device_mid, false0, false0));
97 } else {
98 if (device_final)
99 snprintf(save, LINE_BUF_SIZE1024, "%s: %s %s %s",
100 locate_info(class_mid, false0, true1),
101 locate_info(device_top, false0, false0),
102 locate_info(device_mid, false0, false0),
103 locate_info(device_final, true1, false0));
104 else
105 snprintf(save, LINE_BUF_SIZE1024, "%s: %s %s",
106 locate_info(class_mid, false0, true1),
107 locate_info(device_top, false0, false0),
108 locate_info(device_mid, false0, false0));
109 }
110}
111
112static void format_all(char *save, char *vendor, char *device)
113{
114 if (device_top && device_mid)
115 format_and_print(save);
116
117 else if (device_top && !device_mid && class_mid)
118 snprintf(save, LINE_BUF_SIZE1024, "%s: %s Device %s",
119 locate_info(class_mid, false0, true1),
120 locate_info(device_top, false0, false0),
121 device);
122
123 else if (!device_top && class_mid)
124 snprintf(save, LINE_BUF_SIZE1024, "%s: Vendor %s Device %s",
125 locate_info(class_mid, false0, true1),
126 vendor,
127 device);
128 else
129 snprintf(save, LINE_BUF_SIZE1024, "Unknown device");
130}
131
132static int is_final_match(char *line, char *search)
133{
134 return !memcmp(&line[2], search, 2);
135}
136
137static int is_inner_sub_vendev(char *line, char *search, char *search2)
138{
139 char combine[10];
140 snprintf(combine, sizeof(combine), "%s %s", &search[2], &search2[2]);
141 if (line[0] != '\t' && line[1] != '\t')
142 return 0;
143
144 return !memcmp(combine, &line[2], 9);
145}
146
147static int is_mid_level_match(char *line, char *device, bool_Bool class)
148{
149 if (!class)
150 return !memcmp(&line[1], &device[2], 4);
151
152 return !memcmp(&line[1], device, 2);
153}
154
155static inline bool_Bool is_comment(char *line)
156{
157 return line[0] == '#';
158}
159
160static int is_top_level_match(char *line, const char* device, bool_Bool class)
161{
162 if (line[0] == '\t')
163 return false0;
164 if (line[0] == '#')
165 return false0;
166 if (!class)
167 return !memcmp(line, &device[2], 4);
168 if (line[0] != 'C')
169 return false0;
170 /* Skipping C(SPACE) 0x */
171 return !memcmp(&line[2], &device[2], 2);
172}
173
174static inline int is_tab(char *line)
175{
176 return line[0] == '\t';
177}
178
179static inline int is_class_info(char *line)
180{
181 return !memcmp(line, "# C class", 9);
182}
183
184static void parse_vendor_device(char *line, FILE *file,
185 char *device, char *subdev,
186 char *subven)
187{
188 bool_Bool device_single_found = false0;
189 size_t len;
190
191 while (fgets(line, LINE_BUF_SIZE1024, file) != NULL((void*)0)) {
14
Assuming stream reaches end-of-file here
15
Loop condition is false. Execution continues on line 191
192 len = strlen(line);
193 if (len > 0 && line[len - 1] == '\n')
194 line[len - 1] = '\0';
195 if (is_comment(line))
196 continue;
197 if (!is_tab(line))
198 return;
199
200 if (!device_single_found && is_mid_level_match(line, device, false0)) {
201 device_single_found = true1;
202 device_mid = strdup(line);
203 continue;
204 }
205
206 if (device_single_found && is_inner_sub_vendev(line, subven, subdev)) {
207 device_final = strdup(line);
208 break;
209 }
210 }
211}
212
213static void pull_class_info(char *line, FILE *file, char *class)
214{
215 bool_Bool top_found = false0;
216 bool_Bool mid_found = false0;
217 size_t len;
218
219 while (fgets(line, LINE_BUF_SIZE1024, file) != NULL((void*)0)) {
19
Read function called when stream is in EOF state. Function has no effect
220 len = strlen(line);
221 if (len > 0 && line[len - 1] == '\n')
222 line[len - 1] = '\0';
223 if (!top_found && is_top_level_match(line, class, true1)) {
224 class_top = strdup(line);
225 top_found = true1;
226 continue;
227 }
228 if (!mid_found && top_found &&
229 is_mid_level_match(line, &class[4], true1)) {
230 class_mid = strdup(line);
231 mid_found = true1;
232 continue;
233 }
234 if (top_found && mid_found &&
235 is_final_match(line, &class[6])) {
236 class_final = strdup(line);
237 break;
238 }
239 }
240}
241
242static int read_sys_node(char *where, char *save, size_t savesz)
243{
244 char *new;
245 int fd, ret = 0, len;
246 fd = open(where, O_RDONLY00);
247 if (fd < 0) {
248 if (errno(*__errno_location ()) != ENOENT2) {
249 fprintf(stderrstderr, "Failed to open %s with errno %s\n",
250 where, libnvme_strerror(errno(*__errno_location ())));
251 }
252 return 1;
253 }
254 /* -1 so we can safely use strstr below */
255 len = read(fd, save, savesz - 1);
256 if (!len)
257 ret = 1;
258 else {
259 save[len] = '\0';
260 new = strstr(save, "\n");
261 if (new)
262 new[0] = '\0';
263 }
264 close(fd);
265 return ret;
266}
267
268static FILE *open_pci_ids(void)
269{
270 int i;
271 char *pci_ids_path;
272 FILE *fp;
273
274 const char* pci_ids[] = {
275 "/usr/share/hwdata/pci.ids", /* RHEL */
276 "/usr/share/pci.ids", /* SLES */
277 "/usr/share/misc/pci.ids", /* Ubuntu */
278 NULL((void*)0)
279 };
280
281 /* First check if user gave pci ids in environment */
282 if ((pci_ids_path = getenv("PCI_IDS_PATH")) != NULL((void*)0)) {
283 if ((fp = fopen(pci_ids_path, "r")) != NULL((void*)0)) {
284 return fp;
285 } else {
286 /* fail if user provided environment variable but could not open */
287 perror(pci_ids_path);
288 return NULL((void*)0);
289 }
290 }
291
292 /* NO environment, check in predefined places */
293 for (i = 0; pci_ids[i] != NULL((void*)0); i++) {
294 if ((fp = fopen(pci_ids[i], "r")) != NULL((void*)0))
295 return fp;
296 }
297
298 fprintf(stderrstderr, "Could not find pci.ids file\n");
299 return NULL((void*)0);
300}
301
302static char *__nvme_product_name(int id)
303{
304 char readbuf[LINE_BUF_SIZE1024];
305 char vendor[7] = { 0 };
306 char device[7] = { 0 };
307 char sub_device[7] = { 0 };
308 char sub_vendor[7] = { 0 };
309 char class[13] = { 0 };
310 size_t len;
311 int ret = 0;
312 char *result;
313 FILE *file = open_pci_ids();
314
315 if (!file
7.1
'file' is non-null
)
8
Taking false branch
316 goto error1;
317
318 snprintf(fmt1, 78, _fmt1, id);
319 snprintf(fmt2, 78, _fmt2, id);
320 snprintf(fmt3, 78, _fmt3, id);
321 snprintf(fmt4, 78, _fmt4, id);
322 snprintf(fmt5, 78, _fmt5, id);
323
324 ret = read_sys_node(fmt1, sub_vendor, 7);
325 ret |= read_sys_node(fmt2, sub_device, 7);
326 ret |= read_sys_node(fmt3, vendor, 7);
327 ret |= read_sys_node(fmt4, device, 7);
328 ret |= read_sys_node(fmt5, class, 13);
329 if (ret
8.1
'ret' is 0
)
9
Taking false branch
330 goto error0;
331
332 while (fgets(readbuf, sizeof(readbuf), file) != NULL((void*)0)) {
10
Loop condition is true. Entering loop body
333 len = strlen(readbuf);
334 if (len > 0 && readbuf[len - 1] == '\n')
11
Assuming 'len' is <= 0
335 readbuf[len - 1] = '\0';
336 if (is_comment(readbuf) && !is_class_info(readbuf))
337 continue;
338 if (is_top_level_match(readbuf, vendor, false0)) {
12
Taking true branch
339 free(device_top);
340 device_top = strdup(readbuf);
341 parse_vendor_device(readbuf, file,
13
Calling 'parse_vendor_device'
16
Returning from 'parse_vendor_device'
342 device,
343 sub_device,
344 sub_vendor);
345 }
346 if (is_class_info(readbuf))
17
Taking true branch
347 pull_class_info(readbuf, file, class);
18
Calling 'pull_class_info'
348 }
349 fclose(file);
350
351 result = malloc(LINE_BUF_SIZE1024);
352 if (!result) {
353 fprintf(stderrstderr, "malloc: %s\n", libnvme_strerror(errno(*__errno_location ())));
354 free_all();
355 return NULL((void*)0);
356 }
357 format_all(result, vendor, device);
358 free_all();
359 return result;
360error0:
361 fclose(file);
362error1:
363 return NULL((void*)0);
364}
365
366char *nvme_product_name(const char *devname)
367{
368 const char *base;
369 int id;
370
371 if (!devname)
1
Assuming 'devname' is non-null
2
Taking false branch
372 return NULL((void*)0);
373
374 base = strrchr(devname, '/');
375 if (base) {
3
Assuming 'base' is null
4
Taking false branch
376 if (!base[1])
377 return NULL((void*)0);
378 devname = base + 1;
379 }
380
381 if (sscanf(devname, "nvme%d", &id) != 1)
5
Assuming the condition is false
6
Taking false branch
382 return NULL((void*)0);
383
384 return __nvme_product_name(id);
7
Calling '__nvme_product_name'
385}