Bug Summary

File:s/lib/dbm/src/hash_buf.c
Warning:line 371, column 13
Use of memory after it is freed

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 hash_buf.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 -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -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=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/dbm/src -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/dbm/src -resource-dir /usr/lib/llvm-18/lib/clang/18 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -D STDC_HEADERS -D HAVE_STRERROR -D HAVE_SNPRINTF -D MEMMOVE -D __DBINTERFACE_PRIVATE -I ../../../../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../../dist/public/dbm -I ../../../../dist/private/dbm -internal-isystem /usr/lib/llvm-18/lib/clang/18/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 -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-1 -x c hash_buf.c
1/*-
2 * Copyright (c) 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Margo Seltzer.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. ***REMOVED*** - see
17 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#if defined(LIBC_SCCS) && !defined(lint)
36static char sccsid[] = "@(#)hash_buf.c 8.5 (Berkeley) 7/15/94";
37#endif /* LIBC_SCCS and not lint */
38
39/*
40 * PACKAGE: hash
41 *
42 * DESCRIPTION:
43 * Contains buffer management
44 *
45 * ROUTINES:
46 * External
47 * __buf_init
48 * __get_buf
49 * __buf_free
50 * __reclaim_buf
51 * Internal
52 * newbuf
53 */
54#if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh)
55#include <sys/param.h>
56#endif
57
58#include <errno(*__errno_location ()).h>
59#include <stddef.h>
60#include <stdio.h>
61#include <stdlib.h>
62#include <string.h>
63
64#ifdef DEBUG1
65#include <assert.h>
66#endif
67
68#include "mcom_db.h"
69#include "hash.h"
70#include "page.h"
71/* #include "extern.h" */
72
73static BUFHEAD *newbuf(HTAB *, uint32, BUFHEAD *);
74
75/* Unlink B from its place in the lru */
76#define BUF_REMOVE(B){ (B)->prev->next = (B)->next; (B)->next->prev
= (B)->prev; }
\
77 { \
78 (B)->prev->next = (B)->next; \
79 (B)->next->prev = (B)->prev; \
80 }
81
82/* Insert B after P */
83#define BUF_INSERT(B, P){ (B)->next = (P)->next; (B)->prev = (P); (P)->next
= (B); (B)->next->prev = (B); }
\
84 { \
85 (B)->next = (P)->next; \
86 (B)->prev = (P); \
87 (P)->next = (B); \
88 (B)->next->prev = (B); \
89 }
90
91#define MRUhashp->bufhead.next hashp->bufhead.next
92#define LRUhashp->bufhead.prev hashp->bufhead.prev
93
94#define MRU_INSERT(B){ ((B))->next = (&hashp->bufhead)->next; ((B))->
prev = (&hashp->bufhead); (&hashp->bufhead)->
next = ((B)); ((B))->next->prev = ((B)); }
BUF_INSERT((B), &hashp->bufhead){ ((B))->next = (&hashp->bufhead)->next; ((B))->
prev = (&hashp->bufhead); (&hashp->bufhead)->
next = ((B)); ((B))->next->prev = ((B)); }
95#define LRU_INSERT(B){ ((B))->next = (hashp->bufhead.prev)->next; ((B))->
prev = (hashp->bufhead.prev); (hashp->bufhead.prev)->
next = ((B)); ((B))->next->prev = ((B)); }
BUF_INSERT((B), LRU){ ((B))->next = (hashp->bufhead.prev)->next; ((B))->
prev = (hashp->bufhead.prev); (hashp->bufhead.prev)->
next = ((B)); ((B))->next->prev = ((B)); }
96
97/*
98 * We are looking for a buffer with address "addr". If prev_bp is NULL, then
99 * address is a bucket index. If prev_bp is not NULL, then it points to the
100 * page previous to an overflow page that we are trying to find.
101 *
102 * CAVEAT: The buffer header accessed via prev_bp's ovfl field may no longer
103 * be valid. Therefore, you must always verify that its address matches the
104 * address you are seeking.
105 */
106extern BUFHEAD *
107dbm_get_buf(HTAB *hashp, uint32 addr, BUFHEAD *prev_bp, int newpage)
108/* If prev_bp set, indicates a new overflow page. */
109{
110 register BUFHEAD *bp;
111 register uint32 is_disk_mask;
112 register int is_disk, segment_ndx = 0;
113 SEGMENT segp = 0;
114
115 is_disk = 0;
116 is_disk_mask = 0;
117 if (prev_bp) {
118 bp = prev_bp->ovfl;
119 if (!bp || (bp->addr != addr))
120 bp = NULL((void*)0);
121 if (!newpage)
122 is_disk = BUF_DISK0x0002;
123 } else {
124 /* Grab buffer out of directory */
125 segment_ndx = addr & (hashp->SGSIZEhdr.ssize - 1);
126
127 /* valid segment ensured by dbm_call_hash() */
128 segp = hashp->dir[addr >> hashp->SSHIFThdr.sshift];
129#ifdef DEBUG1
130 assert(segp != NULL)((segp != ((void*)0)) ? (void) (0) : __assert_fail ("segp != NULL"
, "hash_buf.c", 130, __extension__ __PRETTY_FUNCTION__))
;
131#endif
132
133 bp = PTROF(segp[segment_ndx])((ptrdiff_t)(segp[segment_ndx]) == 0x0002 ? 0 : (segp[segment_ndx
]))
;
134
135 is_disk_mask = ISDISK(segp[segment_ndx])((segp[segment_ndx]) ? ((ptrdiff_t)(segp[segment_ndx]) == 0x0002
? 0x0002 : (segp[segment_ndx])->is_disk) : 0)
;
136 is_disk = is_disk_mask || !hashp->new_file;
137 }
138
139 if (!bp) {
140 bp = newbuf(hashp, addr, prev_bp);
141 if (!bp)
142 return (NULL((void*)0));
143 if (dbm_get_page(hashp, bp->page, addr, !prev_bp, is_disk, 0)) {
144 /* free bp and its page */
145 if (prev_bp) {
146 /* if prev_bp is set then the new page that
147 * failed is hooked onto prev_bp as an overflow page.
148 * if we don't remove the pointer to the bad page
149 * we may try and access it later and we will die
150 * horribly because it will have already been
151 * free'd and overwritten with bogus data.
152 */
153 prev_bp->ovfl = NULL((void*)0);
154 }
155 BUF_REMOVE(bp){ (bp)->prev->next = (bp)->next; (bp)->next->prev
= (bp)->prev; }
;
156 free(bp->page);
157 free(bp);
158 return (NULL((void*)0));
159 }
160
161 if (!prev_bp) {
162#if 0
163 /* 16 bit windows and mac can't handle the
164 * oring of the is disk flag.
165 */
166 segp[segment_ndx] =
167 (BUFHEAD *)((ptrdiff_t)bp | is_disk_mask);
168#else
169 /* set the is_disk thing inside the structure
170 */
171 bp->is_disk = is_disk_mask;
172 segp[segment_ndx] = bp;
173#endif
174 }
175 } else {
176 BUF_REMOVE(bp){ (bp)->prev->next = (bp)->next; (bp)->next->prev
= (bp)->prev; }
;
177 MRU_INSERT(bp){ ((bp))->next = (&hashp->bufhead)->next; ((bp))
->prev = (&hashp->bufhead); (&hashp->bufhead
)->next = ((bp)); ((bp))->next->prev = ((bp)); }
;
178 }
179 return (bp);
180}
181
182/*
183 * We need a buffer for this page. Either allocate one, or evict a resident
184 * one (if we have as many buffers as we're allowed) and put this one in.
185 *
186 * If newbuf finds an error (returning NULL), it also sets errno.
187 */
188static BUFHEAD *
189newbuf(HTAB *hashp, uint32 addr, BUFHEAD *prev_bp)
190{
191 register BUFHEAD *bp; /* The buffer we're going to use */
192 register BUFHEAD *xbp; /* Temp pointer */
193 register BUFHEAD *next_xbp;
194 SEGMENT segp;
195 int segment_ndx;
196 uint16 oaddr, *shortp;
197
198 oaddr = 0;
199 bp = LRUhashp->bufhead.prev;
200 /*
201 * If LRU buffer is pinned, the buffer pool is too small. We need to
202 * allocate more buffers.
203 */
204 if (hashp->nbufs || (bp->flags & BUF_PIN0x0008)) {
205 /* Allocate a new one */
206 if ((bp = (BUFHEAD *)malloc(sizeof(BUFHEAD))) == NULL((void*)0))
207 return (NULL((void*)0));
208
209 /* this memset is supposedly unnecessary but lets add
210 * it anyways.
211 */
212 memset(bp, 0xff, sizeof(BUFHEAD));
213
214 if ((bp->page = (char *)malloc((size_t)hashp->BSIZEhdr.bsize)) == NULL((void*)0)) {
215 free(bp);
216 return (NULL((void*)0));
217 }
218
219 /* this memset is supposedly unnecessary but lets add
220 * it anyways.
221 */
222 memset(bp->page, 0xff, (size_t)hashp->BSIZEhdr.bsize);
223
224 if (hashp->nbufs)
225 hashp->nbufs--;
226 } else {
227 /* Kick someone out */
228 BUF_REMOVE(bp){ (bp)->prev->next = (bp)->next; (bp)->next->prev
= (bp)->prev; }
;
229 /*
230 * If this is an overflow page with addr 0, it's already been
231 * flushed back in an overflow chain and initialized.
232 */
233 if ((bp->addr != 0) || (bp->flags & BUF_BUCKET0x0004)) {
234 /*
235 * Set oaddr before __put_page so that you get it
236 * before bytes are swapped.
237 */
238 shortp = (uint16 *)bp->page;
239 if (shortp[0]) {
240 if (shortp[0] > (hashp->BSIZEhdr.bsize / sizeof(uint16))) {
241 return (NULL((void*)0));
242 }
243 oaddr = shortp[shortp[0] - 1];
244 }
245 if ((bp->flags & BUF_MOD0x0001) && dbm_put_page(hashp, bp->page,
246 bp->addr, (int)IS_BUCKET(bp->flags)((bp->flags)&0x0004), 0))
247 return (NULL((void*)0));
248 /*
249 * Update the pointer to this page (i.e. invalidate it).
250 *
251 * If this is a new file (i.e. we created it at open
252 * time), make sure that we mark pages which have been
253 * written to disk so we retrieve them from disk later,
254 * rather than allocating new pages.
255 */
256 if (IS_BUCKET(bp->flags)((bp->flags)&0x0004)) {
257 segment_ndx = bp->addr & (hashp->SGSIZEhdr.ssize - 1);
258 segp = hashp->dir[bp->addr >> hashp->SSHIFThdr.sshift];
259#ifdef DEBUG1
260 assert(segp != NULL)((segp != ((void*)0)) ? (void) (0) : __assert_fail ("segp != NULL"
, "hash_buf.c", 260, __extension__ __PRETTY_FUNCTION__))
;
261#endif
262
263 if (hashp->new_file &&
264 ((bp->flags & BUF_MOD0x0001) ||
265 ISDISK(segp[segment_ndx])((segp[segment_ndx]) ? ((ptrdiff_t)(segp[segment_ndx]) == 0x0002
? 0x0002 : (segp[segment_ndx])->is_disk) : 0)
))
266 segp[segment_ndx] = (BUFHEAD *)BUF_DISK0x0002;
267 else
268 segp[segment_ndx] = NULL((void*)0);
269 }
270 /*
271 * Since overflow pages can only be access by means of
272 * their bucket, free overflow pages associated with
273 * this bucket.
274 */
275 for (xbp = bp; xbp->ovfl;) {
276 next_xbp = xbp->ovfl;
277 xbp->ovfl = 0;
278 xbp = next_xbp;
279
280 /* leave pinned pages alone, we are still using
281 * them. */
282 if (xbp->flags & BUF_PIN0x0008) {
283 continue;
284 }
285
286 /* Check that ovfl pointer is up date. */
287 if (IS_BUCKET(xbp->flags)((xbp->flags)&0x0004) ||
288 (oaddr != xbp->addr))
289 break;
290
291 shortp = (uint16 *)xbp->page;
292 if (shortp[0]) {
293 /* LJM is the number of reported
294 * pages way too much?
295 */
296 if (shortp[0] > hashp->BSIZEhdr.bsize / sizeof(uint16))
297 return NULL((void*)0);
298 /* set before __put_page */
299 oaddr = shortp[shortp[0] - 1];
300 }
301 if ((xbp->flags & BUF_MOD0x0001) && dbm_put_page(hashp,
302 xbp->page, xbp->addr, 0, 0))
303 return (NULL((void*)0));
304 xbp->addr = 0;
305 xbp->flags = 0;
306 BUF_REMOVE(xbp){ (xbp)->prev->next = (xbp)->next; (xbp)->next->
prev = (xbp)->prev; }
;
307 LRU_INSERT(xbp){ ((xbp))->next = (hashp->bufhead.prev)->next; ((xbp
))->prev = (hashp->bufhead.prev); (hashp->bufhead.prev
)->next = ((xbp)); ((xbp))->next->prev = ((xbp)); }
;
308 }
309 }
310 }
311
312 /* Now assign this buffer */
313 bp->addr = addr;
314#ifdef DEBUG1
315 (void)fprintf(stderrstderr, "NEWBUF1: %d->ovfl was %d is now %d\n",
316 bp->addr, (bp->ovfl ? bp->ovfl->addr : 0), 0);
317#endif
318 bp->ovfl = NULL((void*)0);
319 if (prev_bp) {
320/*
321 * If prev_bp is set, this is an overflow page, hook it in to
322 * the buffer overflow links.
323 */
324#ifdef DEBUG1
325 (void)fprintf(stderrstderr, "NEWBUF2: %d->ovfl was %d is now %d\n",
326 prev_bp->addr, (prev_bp->ovfl ? bp->ovfl->addr : 0),
327 (bp ? bp->addr : 0));
328#endif
329 prev_bp->ovfl = bp;
330 bp->flags = 0;
331 } else
332 bp->flags = BUF_BUCKET0x0004;
333 MRU_INSERT(bp){ ((bp))->next = (&hashp->bufhead)->next; ((bp))
->prev = (&hashp->bufhead); (&hashp->bufhead
)->next = ((bp)); ((bp))->next->prev = ((bp)); }
;
334 return (bp);
335}
336
337extern void
338dbm_buf_init(HTAB *hashp, int32 nbytes)
339{
340 BUFHEAD *bfp;
341 int npages;
342
343 bfp = &(hashp->bufhead);
344 npages = (nbytes + hashp->BSIZEhdr.bsize - 1) >> hashp->BSHIFThdr.bshift;
345 npages = PR_MAX(npages, MIN_BUFFERS)((npages)>(6)?(npages):(6));
346
347 hashp->nbufs = npages;
348 bfp->next = bfp;
349 bfp->prev = bfp;
350 /*
351 * This space is calloc'd so these are already null.
352 *
353 * bfp->ovfl = NULL;
354 * bfp->flags = 0;
355 * bfp->page = NULL;
356 * bfp->addr = 0;
357 */
358}
359
360extern int
361dbm_buf_free(HTAB *hashp, int do_free, int to_disk)
362{
363 BUFHEAD *bp;
364 int status = -1;
365
366 /* Need to make sure that buffer manager has been initialized */
367 if (!LRUhashp->bufhead.prev)
1
Assuming field 'prev' is non-null
2
Taking false branch
368 return (0);
369 for (bp = LRUhashp->bufhead.prev; bp != &hashp->bufhead;) {
370 /* Check that the buffer is valid */
371 if (bp->addr || IS_BUCKET(bp->flags)((bp->flags)&0x0004)) {
3
Assuming field 'addr' is not equal to 0
10
Use of memory after it is freed
372 if (to_disk && (bp->flags & BUF_MOD0x0001) &&
4
Assuming 'to_disk' is 0
373 (status = dbm_put_page(hashp, bp->page,
374 bp->addr, IS_BUCKET(bp->flags)((bp->flags)&0x0004), 0))) {
375
376 if (do_free) {
377 if (bp->page)
378 free(bp->page);
379 BUF_REMOVE(bp){ (bp)->prev->next = (bp)->next; (bp)->next->prev
= (bp)->prev; }
;
380 free(bp);
381 }
382
383 return (status);
384 }
385 }
386 /* Check if we are freeing stuff */
387 if (do_free) {
5
Assuming 'do_free' is not equal to 0
6
Taking true branch
388 if (bp->page)
7
Assuming field 'page' is null
8
Taking false branch
389 free(bp->page);
390 BUF_REMOVE(bp){ (bp)->prev->next = (bp)->next; (bp)->next->prev
= (bp)->prev; }
;
391 free(bp);
9
Memory is released
392 bp = LRUhashp->bufhead.prev;
393 } else
394 bp = bp->prev;
395 }
396 return (0);
397}
398
399extern void
400dbm_reclaim_buf(HTAB *hashp, BUFHEAD *bp)
401{
402 bp->ovfl = 0;
403 bp->addr = 0;
404 bp->flags = 0;
405 BUF_REMOVE(bp){ (bp)->prev->next = (bp)->next; (bp)->next->prev
= (bp)->prev; }
;
406 LRU_INSERT(bp){ ((bp))->next = (hashp->bufhead.prev)->next; ((bp))
->prev = (hashp->bufhead.prev); (hashp->bufhead.prev
)->next = ((bp)); ((bp))->next->prev = ((bp)); }
;
407}