Bug Summary

File:programs/cavp/cavp_parser.c
Warning:line 231, column 55
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'cavp')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name cavp_parser.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 2 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/build/quick-libreswan-2/programs/cavp -resource-dir /usr/lib64/clang/13.0.0 -D TimeZoneOffset=timezone -D PIE -D NSS_IPSEC_PROFILE -D XFRM_LIFETIME_DEFAULT=30 -D USE_IKEv1 -D XFRM_SUPPORT -D USE_XFRM_INTERFACE -D USE_DNSSEC -D DEFAULT_DNSSEC_ROOTKEY_FILE="/var/lib/unbound/root.key" -D HAVE_LABELED_IPSEC -D HAVE_SECCOMP -D LIBCURL -D USE_LINUX_AUDIT -D HAVE_NM -D USE_PAM_AUTH -D USE_3DES -D USE_AES -D USE_CAMELLIA -D USE_CHACHA -D USE_DH31 -D USE_MD5 -D USE_SHA1 -D USE_SHA2 -D USE_PRF_AES_XCBC -D USE_NSS_KDF -D DEFAULT_RUNDIR="/run/pluto" -D IPSEC_CONF="/etc/ipsec.conf" -D IPSEC_CONFDDIR="/etc/ipsec.d" -D IPSEC_NSSDIR="/var/lib/ipsec/nss" -D IPSEC_CONFDIR="/etc" -D IPSEC_EXECDIR="/usr/local/libexec/ipsec" -D IPSEC_SBINDIR="/usr/local/sbin" -D IPSEC_VARDIR="/var" -D POLICYGROUPSDIR="/etc/ipsec.d/policies" -D IPSEC_SECRETS_FILE="/etc/ipsec.secrets" -D FORCE_PR_ASSERT -D USE_FORK=1 -D USE_VFORK=0 -D USE_DAEMON=0 -D USE_PTHREAD_SETSCHEDPRIO=1 -D GCC_LINT -D HAVE_LIBCAP_NG -D USE_IKEv1 -I . -I ../../OBJ.linux.x86_64/programs/cavp -I ../../include -I /usr/include/nss3 -I /usr/include/nspr4 -D HERE_FILENAME="programs/cavp/cavp_parser.c" -internal-isystem /usr/lib64/clang/13.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/11/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu99 -fdebug-compilation-dir=/home/build/quick-libreswan-2/programs/cavp -ferror-limit 19 -stack-protector 3 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-01-01-205714-1273399-1 -x c /home/build/quick-libreswan-2/programs/cavp/cavp_parser.c
1/* Parse CAVP test vectors, for libreswan (CAVP)
2 *
3 * Copyright (C) 2015-2018, Andrew Cagney
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16
17#include <stdio.h>
18#include <string.h>
19#include <stdlib.h>
20#include <regex.h>
21
22#include "lswfips.h"
23#include "lswnss.h"
24
25#include "cavp.h"
26#include "cavps.h"
27#include "cavp_entry.h"
28#include "cavp_print.h"
29#include "cavp_parser.h"
30
31enum what { HEADER, BODY, BLANK, CONFIG, DATA, IDLE, END } state = HEADER;
32
33const char *const whats[] = {
34 "HEADER", "BODY", "BLANK", "CONFIG", "DATA", "IDLE", "END",
35};
36
37static void error_state(enum what state, enum what what,
38 const char *message)
39{
40 fprintf(stderrstderr, "\nbad state transition from %s(%d) to %s(%d)\n%s\n",
41 whats[state], state, whats[what], what, message);
42 exit(1);
43}
44
45static void next_state(const struct cavp *cavp, enum what what, struct logger *logger)
46{
47 switch (state) {
48 case HEADER:
49 switch (what) {
50 case BODY:
51 state = what;
52 break;
53 default:
54 error_state(state, what,
55 "expecting header containing file type");
56 }
57 break;
58 case BODY:
59 switch (what) {
60 case CONFIG:
61 state = CONFIG;
62 break;
63 case BLANK:
64 break;
65 default:
66 error_state(state, what, "expecting config section");
67 }
68 break;
69 case CONFIG:
70 switch (what) {
71 case CONFIG:
72 break;
73 case BLANK:
74 cavp->print_config();
75 state = DATA;
76 break;
77 default:
78 error_state(state, what, "expecting data section");
79 }
80 break;
81 case DATA:
82 switch (what) {
83 case DATA:
84 break;
85 case BLANK:
86 cavp->run_test(logger);
87 state = IDLE;
88 break;
89 case END:
90 cavp->run_test(logger);
91 state = END;
92 break;
93 default:
94 error_state(state, what, "expecting EOF or CONFIG section");
95 }
96 break;
97 case IDLE:
98 switch (what) {
99 case CONFIG:
100 state = CONFIG;
101 break;
102 case DATA:
103 state = DATA;
104 break;
105 case END:
106 state = END;
107 break;
108 case BLANK:
109 break;
110 default:
111 error_state(state, what, "expecting config section");
112 }
113 break;
114 default:
115 error_state(state, what, "expecting the unexpected");
116 break;
117 }
118}
119
120struct fields {
121 char *key;
122 char *value;
123};
124
125static struct fields parse_fields(char *line)
126{
127 struct fields fields = {
128 .key = line,
129 };
130 char *eq = strchr(line, '=');
131 if (eq != NULL((void*)0)) {
132 char *ke = eq;
133 while (ke > fields.key && ke[-1] == ' ') {
134 ke--;
135 }
136 *ke = '\0';
137 }
138 if (eq == NULL((void*)0)) {
139 fields.value = NULL((void*)0);
140 } else {
141 fields.value = eq + 1;
142 while (*fields.value == ' ') {
143 fields.value++;
144 }
145 }
146 return fields;
147}
148
149void cavp_parser(const struct cavp *cavp, struct logger *logger)
150{
151 /* size is arbitrary */
152 char line[65536] = "";
153 int line_nr = 0;
154
155 if (cavp != NULL((void*)0)) {
1
Assuming 'cavp' is equal to NULL
2
Taking false branch
156 next_state(cavp, BODY, logger);
157 }
158
159 for (;;) {
3
Loop condition is true. Entering loop body
160 line_nr++;
161 if (fgets(line, sizeof(line), stdinstdin) == NULL((void*)0)) {
4
Assuming the condition is false
5
Taking false branch
162 int error = ferror(stdinstdin);
163 if (error != 0) {
164 fprintf(stderrstderr, "unexpected error at line %d: %s(%d)\n",
165 line_nr, strerror(error), error);
166 exit(1);
167 }
168 break;
169 }
170 if (strlen(line) >= sizeof(line) - 1) {
6
Assuming the condition is false
7
Taking false branch
171 fprintf(stderrstderr, "line %d exceeded buffer length of %zu: %s\n",
172 line_nr, sizeof(line), line);
173 exit(1);
174 }
175 /* trim trailing cr/nl. */
176 int last = strlen(line) - 1;
177 while (last
7.1
'last' is >= 0
>= 0 && strchr("\r\n", line[last]) != NULL((void*)0)) {
8
Assuming the condition is false
9
Loop condition is false. Execution continues on line 180
178 last--;
179 }
180 line[last + 1] = '\0';
181 /* break the line up */
182 if (line[0] == '\0') {
10
Assuming the condition is false
11
Taking false branch
183 next_state(cavp, BLANK, logger);
184 /* blank */
185 print_line(line);
186 } else if (line[0] == '#') {
12
Assuming the condition is false
13
Taking false branch
187 /* # .... comment */
188 if (cavp == NULL((void*)0)) {
189 for (const struct cavp **cavpp = cavps;
190 cavp == NULL((void*)0) && *cavpp != NULL((void*)0);
191 cavpp++) {
192 for (const char *const *match = (*cavpp)->match;
193 cavp == NULL((void*)0) && *match != NULL((void*)0);
194 match++) {
195 regex_t regex;
196 if (regcomp(&regex, *match, REG_EXTENDED1)) {
197 fprintf(stderrstderr, "bad regex %s\n", *match);
198 exit(1);
199 }
200 if (regexec(&regex, line, 0, NULL((void*)0), 0) == 0) {
201 cavp = *cavpp;
202 fprintf(stderrstderr, "\ntest: %s (header matched '%s')\n\n",
203 cavp->description, *match);
204 next_state(cavp, BODY, logger);
205 }
206 regfree(&regex);
207 }
208 }
209 }
210 print_line(line);
211 } else if (line[0] == '[') {
14
Assuming the condition is false
15
Taking false branch
212 next_state(cavp, CONFIG, logger);
213 /* "[" <key> [ " "* "=" " "* <value> ] "]" */
214 char *rparen = strchr(line, ']');
215 *rparen = '\0';
216 struct fields fields = parse_fields(line + 1);
217 const struct cavp_entry *entry = cavp_entry_by_key(cavp->config, fields.key);
218 if (entry == NULL((void*)0)) {
219 fprintf(stderrstderr, "unknown config entry: ['%s' = '%s']\n",
220 fields.key, fields.value);
221 exit(1);
222 } else if (entry->op == NULL((void*)0)) {
223 fprintf(stderrstderr, "ignoring config entry: ['%s' = '%s']\n",
224 fields.key, fields.value);
225 } else {
226 entry->op(entry, fields.value, logger);
227 }
228 } else {
229 next_state(cavp, DATA, logger);
230 struct fields fields = parse_fields(line);
231 const struct cavp_entry *entry = cavp_entry_by_key(cavp->data, fields.key);
16
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'cavp')
232 if (entry == NULL((void*)0)) {
233 fprintf(stderrstderr, "unknown data entry: '%s' = '%s'\n",
234 fields.key, fields.value);
235 exit(1);
236 } else if (entry->op == NULL((void*)0)) {
237 fprintf(stderrstderr, "ignoring data entry: '%s' = '%s'\n",
238 fields.key, fields.value);
239 } else {
240 entry->op(entry, fields.value, logger);
241 }
242 }
243 }
244 next_state(cavp, END, logger);
245}