Bug Summary

File:.build-ci/../keysd/tests/test-config.c
Warning:line 60, column 16
Access to field 'debug_level' results in a dereference of a null pointer (loaded from variable 'cfg')

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 test-config.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 static -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 keysd/tests/test-keysd-config.p -I keysd/tests -I ../keysd/tests -I ../keysd/src -I ccan -I ../ccan -I . -I .. -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-10-24-125112-639-1 -x c ../keysd/tests/test-config.c
1// SPDX-License-Identifier: GPL-2.0-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 <stdbool.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14
15#include <daemon-util/log.h>
16#include <shared/string-util.h>
17
18#include "config.h"
19
20static bool_Bool check(bool_Bool cond, const char *what)
21{
22 printf(" - %s [%s]\n", what, cond ? "PASS" : "FAIL");
23 return cond;
24}
25
26/* Write @text to a temp file and load it as an nvme-keysd config. */
27static struct keysd_config *load_text(const char *text)
28{
29 char path[] = "/tmp/nvme-keysd-config-XXXXXX";
30 struct keysd_config *cfg;
31 size_t len = strlen(text);
32 int fd;
33
34 fd = mkstemp(path);
35 if (fd < 0) {
36 fprintf(stderrstderr, "mkstemp: failed\n");
37 exit(EXIT_FAILURE1);
38 }
39 if (write(fd, text, len) != (ssize_t)len) {
40 fprintf(stderrstderr, "write: failed\n");
41 exit(EXIT_FAILURE1);
42 }
43 close(fd);
44
45 cfg = config_load(path);
46 unlink(path);
47
48 return cfg;
49}
50
51static bool_Bool test_missing_file_defaults(void)
52{
53 struct keysd_config *cfg;
54 bool_Bool pass = true1;
55
56 printf("test_missing_file_defaults:\n");
57
58 cfg = config_load("/nonexistent/nvme-keysd.conf");
2
Value assigned to 'cfg'
59 pass &= check(cfg != NULL((void*)0), "config_load never returns NULL");
3
Assuming 'cfg' is equal to NULL
60 pass &= check(cfg->debug_level == DMN_LOG_INFO,
4
Access to field 'debug_level' results in a dereference of a null pointer (loaded from variable 'cfg')
61 "debug-level defaults to info");
62
63 config_free(cfg);
64
65 return pass;
66}
67
68static bool_Bool test_global_parsed(void)
69{
70 struct keysd_config *cfg;
71 bool_Bool pass = true1;
72
73 printf("test_global_parsed:\n");
74
75 cfg = load_text("[Global]\n"
76 "debug-level = DEBUG\n");
77 pass &= check(cfg->debug_level == DMN_LOG_DEBUG,
78 "debug-level parses, case-insensitive");
79
80 config_free(cfg);
81
82 return pass;
83}
84
85static bool_Bool test_invalid_values_ignored(void)
86{
87 struct keysd_config *cfg;
88 bool_Bool pass = true1;
89
90 printf("test_invalid_values_ignored:\n");
91
92 cfg = load_text("[Global]\n"
93 "debug-level = verbose\n");
94 pass &= check(cfg->debug_level == DMN_LOG_INFO,
95 "unknown debug-level ignored, default kept");
96
97 config_free(cfg);
98
99 return pass;
100}
101
102static bool_Bool test_unknown_key_and_section_ignored(void)
103{
104 struct keysd_config *cfg;
105 bool_Bool pass = true1;
106
107 printf("test_unknown_key_and_section_ignored:\n");
108
109 cfg = load_text("[Global]\n"
110 "bogus-key = 1\n"
111 "debug-level = warn\n"
112 "\n"
113 "[Bogus]\n"
114 "debug-level = debug\n");
115 pass &= check(cfg->debug_level == DMN_LOG_WARN,
116 "valid key applies, other section ignored");
117
118 config_free(cfg);
119
120 return pass;
121}
122
123static bool_Bool test_malformed_line_ignored(void)
124{
125 struct keysd_config *cfg;
126 bool_Bool pass = true1;
127
128 printf("test_malformed_line_ignored:\n");
129
130 cfg = load_text("[Global]\n"
131 "not a key value line\n"
132 "debug-level = warn\n");
133 pass &= check(cfg->debug_level == DMN_LOG_WARN,
134 "malformed line skipped, next line applies");
135
136 config_free(cfg);
137
138 return pass;
139}
140
141static bool_Bool test_unreadable_file_defaults(void)
142{
143 struct keysd_config *cfg;
144 bool_Bool pass = true1;
145
146 printf("test_unreadable_file_defaults:\n");
147
148 cfg = config_load("/");
149 pass &= check(cfg != NULL((void*)0), "a directory as config file");
150 pass &= check(cfg->debug_level == DMN_LOG_INFO,
151 "debug-level defaults to info");
152
153 config_free(cfg);
154
155 return pass;
156}
157
158static bool_Bool test_kmip_parsed(void)
159{
160 const struct keysd_kmip *kms;
161 struct keysd_config *cfg;
162 bool_Bool pass = true1;
163
164 printf("test_kmip_parsed:\n");
165
166 cfg = load_text("[kmip:primary]\n"
167 "server = kms1.example.com\n"
168 "server = kms2.example.com\n"
169 "server = kms1.example.com\n"
170 "port = 5697\n"
171 "ca = /etc/nvme/kmip/ca.pem\n"
172 "client-cert = /etc/nvme/kmip/client.pem\n"
173 "client-key = primary\n"
174 "timeout = 500ms\n"
175 "\n"
176 "[kmip:backup]\n"
177 "server = 192.0.2.1\n");
178 pass &= check(cfg->nr_kmip == 2 &&
179 shr_streq0(cfg->kmip[0].name, "primary") &&
180 shr_streq0(cfg->kmip[1].name, "backup"),
181 "two KMSes, in the order of the file");
182
183 kms = config_find_kmip(cfg, "primary");
184 pass &= check(kms && kms->nr_servers == 2 &&
185 shr_streq0(kms->servers[0], "kms1.example.com") &&
186 shr_streq0(kms->servers[1], "kms2.example.com") &&
187 shr_streq0(kms->port, "5697") &&
188 shr_streq0(kms->ca, "/etc/nvme/kmip/ca.pem") &&
189 shr_streq0(kms->client_cert,
190 "/etc/nvme/kmip/client.pem") &&
191 shr_streq0(kms->client_key, "primary") &&
192 kms->timeout_ms == 500,
193 "all keys parsed");
194
195 kms = config_find_kmip(cfg, "backup");
196 pass &= check(kms && shr_streq0(kms->port, KEYSD_KMIP_PORT"5696") &&
197 !kms->ca && !kms->client_cert && !kms->client_key &&
198 kms->timeout_ms == KEYSD_KMIP_TIMEOUT_MS10000,
199 "defaults");
200 pass &= check(!config_find_kmip(cfg, "other"), "unknown name");
201
202 config_free(cfg);
203
204 return pass;
205}
206
207static bool_Bool test_kmip_invalid(void)
208{
209 const struct keysd_kmip *kms;
210 struct keysd_config *cfg;
211 bool_Bool pass = true1;
212
213 printf("test_kmip_invalid:\n");
214
215 cfg = load_text("[kmip:a]\n"
216 "server = kms-a\n"
217 "server = kms a\n"
218 "port = 0\n"
219 "ca = ca.pem\n"
220 "client-key = ../key\n"
221 "timeout = 1h\n"
222 "bogus = 1\n"
223 "\n"
224 "[kmip:a]\n"
225 "server = kms-dup\n"
226 "\n"
227 "[kmip:b/c]\n"
228 "server = kms-bc\n"
229 "\n"
230 "[kmip:no-server]\n"
231 "port = 5696\n"
232 "\n"
233 "[kmip:cert-only]\n"
234 "server = kms-cert\n"
235 "client-cert = /etc/nvme/kmip/client.pem\n");
236 pass &= check(cfg->nr_kmip == 1, "invalid sections dropped");
237
238 kms = config_find_kmip(cfg, "a");
239 pass &= check(kms && kms->nr_servers == 1 &&
240 shr_streq0(kms->servers[0], "kms-a"),
241 "duplicate section and invalid server ignored");
242 pass &= check(kms && shr_streq0(kms->port, KEYSD_KMIP_PORT"5696") &&
243 !kms->ca && !kms->client_key &&
244 kms->timeout_ms == KEYSD_KMIP_TIMEOUT_MS10000,
245 "invalid values ignored");
246
247 config_free(cfg);
248
249 return pass;
250}
251
252int main(void)
253{
254 bool_Bool pass = true1;
255
256 pass &= test_missing_file_defaults();
1
Calling 'test_missing_file_defaults'
257 pass &= test_global_parsed();
258 pass &= test_invalid_values_ignored();
259 pass &= test_unknown_key_and_section_ignored();
260 pass &= test_malformed_line_ignored();
261 pass &= test_unreadable_file_defaults();
262 pass &= test_kmip_parsed();
263 pass &= test_kmip_invalid();
264
265 fflush(stdoutstdout);
266 exit(pass ? EXIT_SUCCESS0 : EXIT_FAILURE1);
267}