Bug Summary

File:.build-ci/../libnvme/src/nvme/util-fabrics.c
Warning:line 62, column 4
Opened stream never closed. Potential resource leak

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 util-fabrics.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 -fhalf-no-semantic-interposition -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 libnvme/src/libnvme3.so.3.0.0.p -I libnvme/src -I ../libnvme/src -I ccan -I ../ccan -I . -I .. -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 -fvisibility=hidden -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 ../libnvme/src/nvme/util-fabrics.c
1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * This file is part of libnvme.
4 * Copyright (c) 2026, Dell Technologies Inc. or its subsidiaries.
5 *
6 * Authors: Martin Belanger <Martin.Belanger@dell.com>
7 */
8
9#include <unistd.h>
10
11#include <ccan/endian/endian.h>
12#include <ccan/minmax/minmax.h>
13
14#include <libnvme.h>
15
16#include "cleanup-linux.h"
17#include "private-fabrics.h"
18#include "util.h"
19
20#include "compiler-attributes.h"
21
22__libnvme_public__attribute__((visibility("default"))) struct nvmf_ext_attr *libnvmf_exat_ptr_next(
23 struct nvmf_ext_attr *p)
24{
25 __u16 size = libnvmf_exat_size(le16_to_cpu(p->exatlen));
26
27 return (struct nvmf_ext_attr *)((uintptr_t)p + (ptrdiff_t)size);
28}
29
30const struct ifaddrs *libnvmf_getifaddrs(struct libnvme_global_ctx *ctx)
31{
32 if (!ctx->ifaddrs_cache) {
33 struct ifaddrs *p;
34
35 if (!getifaddrs(&p))
36 ctx->ifaddrs_cache = p;
37 }
38
39 return ctx->ifaddrs_cache;
40}
41
42/**
43 * read_file - read contents of file into @buffer.
44 * @fname: File name
45 * @buffer: Where to save file's contents
46 * @bufsz: Size of @buffer. On success, @bufsz gets decremented by the
47 * number of characters that were writtent to @buffer.
48 *
49 * Return: The number of characters read. If the file cannot be opened or
50 * nothing is read from the file, then this function returns 0.
51 */
52static size_t read_file(const char * fname, char *buffer, size_t *bufsz)
53{
54 char *p;
55 __cleanup_file__attribute__((cleanup(cleanup_file))) FILE *file = NULL((void*)0);
56 size_t len;
57
58 file = fopen(fname, "re");
2
Stream opened here
3
Assuming that 'fopen' is successful
59 if (!file
3.1
'file' is non-null
)
4
Taking false branch
60 return 0;
61
62 p = fgets(buffer, *bufsz, file);
5
Assuming that the 3rd argument to 'fgets' is not NULL
6
Opened stream never closed. Potential resource leak
63
64 if (!p)
65 return 0;
66
67 /* Strip unwanted trailing chars */
68 len = strcspn(buffer, " \t\n\r");
69 *bufsz -= len;
70
71 return len;
72}
73
74static size_t copy_value(char *buf, size_t buflen, const char *value)
75{
76 size_t val_len;
77
78 memset(buf, 0, buflen);
79
80 /* Remove leading " */
81 if (value[0] == '"')
82 value++;
83
84 /* Remove trailing " */
85 val_len = strcspn(value, "\"");
86
87 memcpy(buf, value, min(val_len, buflen-1)({ typeof(val_len) _a = (val_len); typeof(buflen-1) _b = (buflen
-1); do { } while (0); _a < _b ? _a : _b; })
);
88
89 return val_len;
90}
91
92size_t libnvmf_get_entity_name(char *buffer, size_t bufsz)
93{
94 size_t len = !gethostname(buffer, bufsz) ? strlen(buffer) : 0;
95
96 /* Fill the rest of buffer with zeros */
97 memset(&buffer[len], '\0', bufsz-len);
98
99 return len;
100}
101
102size_t libnvmf_get_entity_version(char *buffer, size_t bufsz)
103{
104 __cleanup_file__attribute__((cleanup(cleanup_file))) FILE *file = NULL((void*)0);
105 size_t num_bytes = 0;
106
107 /* /proc/sys/kernel/ostype typically contains the string "Linux" */
108 num_bytes += read_file("/proc/sys/kernel/ostype",
1
Calling 'read_file'
109 &buffer[num_bytes], &bufsz);
110
111 /* /proc/sys/kernel/osrelease contains the Linux
112 * version (e.g. 5.8.0-63-generic)
113 */
114 buffer[num_bytes++] = ' '; /* Append a space */
115 num_bytes += read_file("/proc/sys/kernel/osrelease",
116 &buffer[num_bytes], &bufsz);
117
118 /* /etc/os-release contains Key-Value pairs. We only care about the key
119 * PRETTY_NAME, which contains the Distro's version. For example:
120 * "SUSE Linux Enterprise Server 15 SP4", "Ubuntu 20.04.3 LTS", or
121 * "Fedora Linux 35 (Server Edition)"
122 */
123 file = fopen("/etc/os-release", "re");
124 if (file) {
125 char name[64] = {0};
126 size_t name_len = 0;
127 char ver_id[64] = {0};
128 size_t ver_id_len = 0;
129 char line[LINE_MAX2048];
130 char *p;
131 char *s;
132
133 /* Read key-value pairs one line at a time */
134 while ((!name_len || !ver_id_len) &&
135 (p = fgets(line, sizeof(line), file)) != NULL((void*)0)) {
136 /* Clean up string by removing leading/trailing blanks
137 * and new line characters. Also eliminate trailing
138 * comments, if any.
139 */
140 p = kv_strip(p);
141
142 /* Empty string? */
143 if (*p == '\0')
144 continue;
145
146 s = kv_keymatch(p, "NAME");
147 if (s)
148 name_len = copy_value(name, sizeof(name), s);
149
150 s = kv_keymatch(p, "VERSION_ID");
151 if (s)
152 ver_id_len = copy_value(ver_id, sizeof(ver_id), s);
153 }
154
155 if (name_len) {
156 /* Append a space */
157 buffer[num_bytes++] = ' ';
158 name_len = min(name_len, bufsz)({ typeof(name_len) _a = (name_len); typeof(bufsz) _b = (bufsz
); do { } while (0); _a < _b ? _a : _b; })
;
159 memcpy(&buffer[num_bytes], name, name_len);
160 bufsz -= name_len;
161 num_bytes += name_len;
162 }
163
164 if (ver_id_len) {
165 /* Append a space */
166 buffer[num_bytes++] = ' ';
167 ver_id_len = min(ver_id_len, bufsz)({ typeof(ver_id_len) _a = (ver_id_len); typeof(bufsz) _b = (
bufsz); do { } while (0); _a < _b ? _a : _b; })
;
168 memcpy(&buffer[num_bytes], ver_id, ver_id_len);
169 bufsz -= ver_id_len;
170 num_bytes += ver_id_len;
171 }
172 }
173
174 /* Fill the rest of buffer with zeros */
175 memset(&buffer[num_bytes], '\0', bufsz);
176
177 return num_bytes;
178}