Bug Summary

File:src/lib/libc/asr/res_search_async.c
Warning:line 141, column 8
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name res_search_async.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 1 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/lib/libc/obj -resource-dir /usr/local/lib/clang/13.0.0 -include namespace.h -I /usr/src/lib/libc/include -I /usr/src/lib/libc/hidden -D __LIBC__ -D APIWARN -D YP -I /usr/src/lib/libc/yp -I /usr/src/lib/libc -I /usr/src/lib/libc/gdtoa -I /usr/src/lib/libc/arch/amd64/gdtoa -D INFNAN_CHECK -D MULTIPLE_THREADS -D NO_FENV_H -D USE_LOCALE -I /usr/src/lib/libc -I /usr/src/lib/libc/citrus -D RESOLVSORT -D FLOATING_POINT -D PRINTF_WIDE_CHAR -D SCANF_WIDE_CHAR -D FUTEX -D PIC -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libc/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/lib/libc/asr/res_search_async.c
1/* $OpenBSD: res_search_async.c,v 1.21 2017/02/27 10:44:46 jca Exp $ */
2/*
3 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <sys/uio.h>
21#include <arpa/nameser.h>
22#include <netdb.h>
23
24#include <asr.h>
25#include <errno(*__errno()).h>
26#include <resolv.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30
31#include "asr_private.h"
32
33static int res_search_async_run(struct asr_query *, struct asr_result *);
34static size_t domcat(const char *, const char *, char *, size_t);
35
36/*
37 * Unlike res_query_async(), this function returns a valid packet only if
38 * h_errno is NETDB_SUCCESS.
39 */
40struct asr_query *
41res_search_async(const char *name, int class, int type, void *asr)
42{
43 struct asr_ctx *ac;
44 struct asr_query *as;
45
46 DPRINT("asr: res_search_async(\"%s\", %i, %i)\n", name, class, type);
47
48 ac = _asr_use_resolver(asr);
49 as = _res_search_async_ctx(name, class, type, ac);
50 _asr_ctx_unref(ac);
51
52 return (as);
53}
54DEF_WEAK(res_search_async)__asm__(".weak " "res_search_async" " ; " "res_search_async" " = "
"_libc_res_search_async")
;
55
56struct asr_query *
57_res_search_async_ctx(const char *name, int class, int type, struct asr_ctx *ac)
58{
59 struct asr_query *as;
60
61 DPRINT("asr: res_search_async_ctx(\"%s\", %i, %i)\n", name, class,
62 type);
63
64 if ((as = _asr_async_new(ac, ASR_SEARCH)) == NULL((void *)0))
65 goto err; /* errno set */
66 as->as_run = res_search_async_run;
67 if ((as->as.search.name = strdup(name)) == NULL((void *)0))
68 goto err; /* errno set */
69
70 as->as.search.class = class;
71 as->as.search.type = type;
72
73 return (as);
74 err:
75 if (as)
76 _asr_async_free(as);
77 return (NULL((void *)0));
78}
79
80#define HERRNO_UNSET-2 -2
81
82static int
83res_search_async_run(struct asr_query *as, struct asr_result *ar)
84{
85 int r;
86 char fqdn[MAXDNAME1025];
87
88 next:
89 switch (as->as_state) {
90
91 case ASR_STATE_INIT:
92
93 if (as->as.search.name[0] == '\0') {
94 ar->ar_h_errno = NO_DATA4;
95 async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0);
96 break;
97 }
98
99 as->as.search.saved_h_errno = HERRNO_UNSET-2;
100 async_set_state(as, ASR_STATE_NEXT_DOMAIN)do { ; (as)->as_state = (ASR_STATE_NEXT_DOMAIN); } while (
0)
;
101 break;
102
103 case ASR_STATE_NEXT_DOMAIN:
104 /*
105 * Reset flags to be able to identify the case in
106 * STATE_SUBQUERY.
107 */
108 as->as_dom_flags = 0;
109
110 r = _asr_iter_domain(as, as->as.search.name, fqdn, sizeof(fqdn));
111 if (r == -1) {
112 async_set_state(as, ASR_STATE_NOT_FOUND)do { ; (as)->as_state = (ASR_STATE_NOT_FOUND); } while (0);
113 break;
114 }
115 if (r == 0) {
116 ar->ar_errno = EINVAL22;
117 ar->ar_h_errno = NO_RECOVERY3;
118 ar->ar_datalen = -1;
119 ar->ar_data = NULL((void *)0);
120 async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0);
121 break;
122 }
123 as->as_subq = _res_query_async_ctx(fqdn,
124 as->as.search.class, as->as.search.type, as->as_ctx);
125 if (as->as_subq == NULL((void *)0)) {
126 ar->ar_errno = errno(*__errno());
127 if (errno(*__errno()) == EINVAL22)
128 ar->ar_h_errno = NO_RECOVERY3;
129 else
130 ar->ar_h_errno = NETDB_INTERNAL-1;
131 ar->ar_datalen = -1;
132 ar->ar_data = NULL((void *)0);
133 async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0);
134 break;
135 }
136 async_set_state(as, ASR_STATE_SUBQUERY)do { ; (as)->as_state = (ASR_STATE_SUBQUERY); } while (0);
137 break;
138
139 case ASR_STATE_SUBQUERY:
140
141 if ((r = asr_run(as->as_subq, ar)) == ASYNC_COND0)
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r'
142 return (ASYNC_COND0);
143 as->as_subq = NULL((void *)0);
144
145 if (ar->ar_h_errno == NETDB_SUCCESS0) {
146 async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0);
147 break;
148 }
149
150 /*
151 * The original res_search() does this in the domain search
152 * loop, but only for ECONNREFUSED. I think we can do better
153 * because technically if we get an errno, it means
154 * we couldn't reach any nameserver, so there is no point
155 * in trying further.
156 */
157 if (ar->ar_errno) {
158 async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0);
159 break;
160 }
161
162 free(ar->ar_data);
163
164 /*
165 * The original resolver does something like this.
166 */
167 if (as->as_dom_flags & ASYNC_DOM_NDOTS0x00000002)
168 as->as.search.saved_h_errno = ar->ar_h_errno;
169
170 if (as->as_dom_flags & ASYNC_DOM_DOMAIN0x00000004) {
171 if (ar->ar_h_errno == NO_DATA4)
172 as->as_flags |= ASYNC_NODATA0x00000100;
173 else if (ar->ar_h_errno == TRY_AGAIN2)
174 as->as_flags |= ASYNC_AGAIN0x00000200;
175 }
176
177 async_set_state(as, ASR_STATE_NEXT_DOMAIN)do { ; (as)->as_state = (ASR_STATE_NEXT_DOMAIN); } while (
0)
;
178 break;
179
180 case ASR_STATE_NOT_FOUND:
181
182 if (as->as.search.saved_h_errno != HERRNO_UNSET-2)
183 ar->ar_h_errno = as->as.search.saved_h_errno;
184 else if (as->as_flags & ASYNC_NODATA0x00000100)
185 ar->ar_h_errno = NO_DATA4;
186 else if (as->as_flags & ASYNC_AGAIN0x00000200)
187 ar->ar_h_errno = TRY_AGAIN2;
188 /*
189 * Else, we got the ar_h_errno value set by res_query_async()
190 * for the last domain.
191 */
192 ar->ar_datalen = -1;
193 ar->ar_data = NULL((void *)0);
194 async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0);
195 break;
196
197 case ASR_STATE_HALT:
198
199 return (ASYNC_DONE1);
200
201 default:
202 ar->ar_errno = EOPNOTSUPP45;
203 ar->ar_h_errno = NETDB_INTERNAL-1;
204 async_set_state(as, ASR_STATE_HALT)do { ; (as)->as_state = (ASR_STATE_HALT); } while (0);
205 break;
206 }
207 goto next;
208}
209
210/*
211 * Concatenate a name and a domain name. The result has no trailing dot.
212 * Return the resulting string length, or 0 in case of error.
213 */
214static size_t
215domcat(const char *name, const char *domain, char *buf, size_t buflen)
216{
217 size_t r;
218
219 r = _asr_make_fqdn(name, domain, buf, buflen);
220 if (r == 0)
221 return (0);
222 buf[r - 1] = '\0';
223
224 return (r - 1);
225}
226
227enum {
228 DOM_INIT,
229 DOM_DOMAIN,
230 DOM_DONE
231};
232
233/*
234 * Implement the search domain strategy.
235 *
236 * This function works as a generator that constructs complete domains in
237 * buffer "buf" of size "len" for the given host name "name", according to the
238 * search rules defined by the resolving context. It is supposed to be called
239 * multiple times (with the same name) to generate the next possible domain
240 * name, if any.
241 *
242 * It returns -1 if all possibilities have been exhausted, 0 if there was an
243 * error generating the next name, or the resulting name length.
244 */
245int
246_asr_iter_domain(struct asr_query *as, const char *name, char * buf, size_t len)
247{
248 const char *c;
249 int dots;
250
251 switch (as->as_dom_step) {
252
253 case DOM_INIT:
254 /* First call */
255
256 /*
257 * If "name" is an FQDN, that's the only result and we
258 * don't try anything else.
259 */
260 if (strlen(name) && name[strlen(name) - 1] == '.') {
261 DPRINT("asr: iter_domain(\"%s\") fqdn\n", name);
262 as->as_dom_flags |= ASYNC_DOM_FQDN0x00000001;
263 as->as_dom_step = DOM_DONE;
264 return (domcat(name, NULL((void *)0), buf, len));
265 }
266
267 /*
268 * Otherwise, we iterate through the specified search domains.
269 */
270 as->as_dom_step = DOM_DOMAIN;
271 as->as_dom_idx = 0;
272
273 /*
274 * If "name" as enough dots, use it as-is first, as indicated
275 * in resolv.conf(5).
276 */
277 dots = 0;
278 for (c = name; *c; c++)
279 dots += (*c == '.');
280 if (dots >= as->as_ctx->ac_ndots) {
281 DPRINT("asr: iter_domain(\"%s\") ndots\n", name);
282 as->as_dom_flags |= ASYNC_DOM_NDOTS0x00000002;
283 if (strlcpy(buf, name, len) >= len)
284 return (0);
285 return (strlen(buf));
286 }
287 /* Otherwise, starts using the search domains */
288 /* FALLTHROUGH */
289
290 case DOM_DOMAIN:
291 if (as->as_dom_idx < as->as_ctx->ac_domcount &&
292 (as->as_ctx->ac_options & RES_DNSRCH0x00000200 || (
293 as->as_ctx->ac_options & RES_DEFNAMES0x00000080 &&
294 as->as_dom_idx == 0 &&
295 strchr(name, '.') == NULL((void *)0)))) {
296 DPRINT("asr: iter_domain(\"%s\") domain \"%s\"\n",
297 name, as->as_ctx->ac_dom[as->as_dom_idx]);
298 as->as_dom_flags |= ASYNC_DOM_DOMAIN0x00000004;
299 return (domcat(name,
300 as->as_ctx->ac_dom[as->as_dom_idx++], buf, len));
301 }
302
303 /* No more domain to try. */
304
305 as->as_dom_step = DOM_DONE;
306
307 /*
308 * If the name was not tried as an absolute name before,
309 * do it now.
310 */
311 if (!(as->as_dom_flags & ASYNC_DOM_NDOTS0x00000002)) {
312 DPRINT("asr: iter_domain(\"%s\") as is\n", name);
313 as->as_dom_flags |= ASYNC_DOM_ASIS0x00000008;
314 if (strlcpy(buf, name, len) >= len)
315 return (0);
316 return (strlen(buf));
317 }
318 /* Otherwise, we are done. */
319
320 case DOM_DONE:
321 default:
322 DPRINT("asr: iter_domain(\"%s\") done\n", name);
323 return (-1);
324 }
325}