Bug Summary

File:.build-ci/../shared/fs-util.c
Warning:line 114, column 7
Potential leak of memory pointed to by 'file_path'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name fs-util.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/bin/../lib/clang/22 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I shared/libshared.a.p -I shared -I ../shared -I ccan -I ../ccan -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu11 -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 -fdwarf2-cfi-asm -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-09-23-073103-589-1 -x c ../shared/fs-util.c
1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * This file is part of nvme-cli.
4 * Copyright (c) 2026 Dell Technologies Inc. or its subsidiaries.
5 *
6 * Authors: Martin Belanger <martin.belanger@dell.com>
7 */
8
9#include <errno(*__errno_location ()).h>
10#include <limits.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <sys/stat.h>
15
16#include "cleanup-util.h"
17#include "fs-util.h"
18
19int shr_mkdir_p(const char *path, mode_t mode)
20{
21 char buf[PATH_MAX4096];
22 char *p;
23 size_t len;
24 int ret;
25
26 len = strlen(path);
27 if (len >= sizeof(buf))
28 return -ENAMETOOLONG36;
29 memcpy(buf, path, len + 1);
30 if (len && buf[len - 1] == '/')
31 buf[len - 1] = '\0';
32
33 for (p = buf + 1; *p; p++) {
34 if (*p != '/')
35 continue;
36 *p = '\0';
37 ret = shr_mkdir(buf, mode);
38 *p = '/';
39 if (ret < 0 && ret != -EEXIST17)
40 return ret;
41 }
42 ret = shr_mkdir(buf, mode);
43 return (ret == 0 || ret == -EEXIST17) ? 0 : ret;
44}
45
46int shr_mkdir_from_fname(const char *file, mode_t mode)
47{
48 __cleanup_free__attribute__((cleanup(shr_freep))) char *file_copy = NULL((void*)0);
49 char *parent;
50 size_t len = strlen(file);
51
52 /*
53 * A trailing '/' means there is no file name to strip and the path is
54 * a directory in full. dirname() cannot be used for it: it removes
55 * the trailing '/' before the last component, so "a/b/" would come
56 * back as "a" and leave "a/b" uncreated.
57 */
58 if (len && file[len - 1] == '/')
59 return shr_mkdir_p(file, mode);
60
61 file_copy = strdup(file);
62 if (!file_copy)
63 return -ENOMEM12;
64
65 parent = shr_dirname(file_copy);
66 return shr_mkdir_p(parent, mode);
67}
68
69char *shr_basename(const char *path)
70{
71 char *p = (char *)strrchr(path, '/')_Generic (0 ? (path) : (void *) 1, const void *: (const char *
) (strrchr (path, '/')), default: strrchr (path, '/'))
;
72
73 return p ? p + 1 : (char *)path;
74}
75
76size_t shr_dir_prefix_len(const char *path)
77{
78 return (size_t)(shr_basename(path) - path);
79}
80
81static char *join_path(const char *dir, const char *path)
82{
83 char *out;
84 size_t len;
85
86 if (!dir)
3
Assuming 'dir' is null
4
Taking true branch
87 return strdup(path);
5
Memory is allocated
88 if (!path || !*path)
89 return strdup(dir);
90
91 len = strlen(dir) + 1 + strlen(path) + 1;
92 out = malloc(len);
93 if (!out)
94 return NULL((void*)0);
95 snprintf(out, len, "%s/%s", dir, path);
96
97 return out;
98}
99
100int shr_read_file(const char *dir, const char *path, long *size,
101 unsigned char **out)
102{
103 __cleanup_free__attribute__((cleanup(shr_freep))) char *file_path = NULL((void*)0);
104 unsigned char *buf;
105 FILE *file;
106 long file_size;
107 size_t n;
108 int ret;
109
110 file_path = join_path(dir, path);
2
Calling 'join_path'
6
Returned allocated memory
111 if (!file_path)
7
Assuming 'file_path' is non-null
8
Taking false branch
112 return -ENOMEM12;
113
114 file = fopen(file_path, "rb");
9
Potential leak of memory pointed to by 'file_path'
115 if (!file)
116 return -errno(*__errno_location ());
117
118 if (fseek(file, 0, SEEK_END2) != 0 || (file_size = ftell(file)) < 0) {
119 ret = -errno(*__errno_location ());
120 goto close_file;
121 }
122 if (file_size == 0) {
123 ret = -ENODATA61;
124 goto close_file;
125 }
126 if (fseek(file, 0, SEEK_SET0) != 0) {
127 ret = -errno(*__errno_location ());
128 goto close_file;
129 }
130
131 buf = malloc(file_size);
132 if (!buf) {
133 ret = -ENOMEM12;
134 goto close_file;
135 }
136
137 n = fread(buf, 1, file_size, file);
138 if (n != (size_t)file_size) {
139 free(buf);
140 ret = -EIO5;
141 goto close_file;
142 }
143
144 *size = file_size;
145 *out = buf;
146 ret = 0;
147
148close_file:
149 fclose(file);
150 return ret;
151}
152
153int shr_read_file_as_string(const char *dir, const char *path, long *size,
154 char **out)
155{
156 unsigned char *raw = NULL((void*)0);
157 char *str;
158 long raw_size = 0;
159 int ret;
160
161 ret = shr_read_file(dir, path, &raw_size, &raw);
1
Calling 'shr_read_file'
162 if (ret < 0 && ret != -ENODATA61)
163 return ret;
164
165 str = realloc(raw, raw_size + 1);
166 if (!str) {
167 free(raw);
168 return -ENOMEM12;
169 }
170 str[raw_size] = '\0';
171
172 if (size)
173 *size = raw_size;
174
175 *out = str;
176 return 0;
177}