Bug Summary

File:root/firefox-clang/security/nss/lib/base/hash.c
Warning:line 51, column 39
Subtraction of a probably non-null pointer and a null pointer may result in undefined behavior

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name hash.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 -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/security/nss/lib/base/base_nssb -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/security/nss/lib/base/base_nssb -resource-dir /usr/lib/llvm-22/lib/clang/22 -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG -D NSS_FIPS_DISABLED -D NSS_NO_INIT_SUPPORT -D NSS_X86_OR_X64 -D NSS_X64 -D NSS_USE_64 -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -D LINUX2_1 -D LINUX -D linux -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D HAVE_STRERROR -D XP_UNIX -D _REENTRANT -D NSS_DISABLE_DBM -D NSS_DISABLE_LIBPKIX -I /root/firefox-clang/security/nss/lib/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/security/nss/lib/base/base_nssb -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/private/nss -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -D MOZILLA_CLIENT -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/15/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=tautological-type-limit-compare -Wno-range-loop-analysis -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-unknown-warning-option -Wno-character-conversion -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-01-01-094441-2823109-1 -x c /root/firefox-clang/security/nss/lib/base/hash.c
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5/*
6 * hash.c
7 *
8 * This is merely a couple wrappers around NSPR's PLHashTable, using
9 * the identity hash and arena-aware allocators.
10 * This is a copy of ckfw/hash.c, with modifications to use NSS types
11 * (not Cryptoki types). Would like for this to be a single implementation,
12 * but doesn't seem like it will work.
13 */
14
15#ifndef BASE_H
16#include "base.h"
17#endif /* BASE_H */
18
19#include "prbit.h"
20
21/*
22 * nssHash
23 *
24 * nssHash_Create
25 * nssHash_Destroy
26 * nssHash_Add
27 * nssHash_Remove
28 * nssHash_Count
29 * nssHash_Exists
30 * nssHash_Lookup
31 * nssHash_Iterate
32 */
33
34struct nssHashStr {
35 NSSArena *arena;
36 PRBool i_alloced_arena;
37 PRLock *mutex;
38
39 /*
40 * The invariant that mutex protects is:
41 * The count accurately reflects the hashtable state.
42 */
43
44 PLHashTable *plHashTable;
45 PRUint32 count;
46};
47
48static PLHashNumber
49nss_identity_hash(const void *key)
50{
51 return (PLHashNumber)((char *)key - (char *)NULL((void*)0));
Subtraction of a probably non-null pointer and a null pointer may result in undefined behavior
52}
53
54static PLHashNumber
55nss_item_hash(const void *key)
56{
57 unsigned int i;
58 PLHashNumber h;
59 NSSItem *it = (NSSItem *)key;
60 h = 0;
61 for (i = 0; i < it->size; i++)
62 h = PR_ROTATE_LEFT32(h, 4)(((h) << (4)) | ((h) >> (32 - (4)))) ^ ((unsigned char *)it->data)[i];
63 return h;
64}
65
66static int
67nss_compare_items(const void *v1, const void *v2)
68{
69 PRStatus ignore;
70 return (int)nssItem_Equal((NSSItem *)v1, (NSSItem *)v2, &ignore);
71}
72
73/*
74 * nssHash_create
75 *
76 */
77NSS_IMPLEMENT nssHash *
78nssHash_Create(NSSArena *arenaOpt, PRUint32 numBuckets, PLHashFunction keyHash,
79 PLHashComparator keyCompare, PLHashComparator valueCompare)
80{
81 nssHash *rv;
82 NSSArena *arena;
83 PRBool i_alloced;
84
85#ifdef NSSDEBUG
86 if (arenaOpt && PR_SUCCESS != nssArena_verifyPointer(arenaOpt)) {
87 nss_SetError(NSS_ERROR_INVALID_POINTER);
88 return (nssHash *)NULL((void*)0);
89 }
90#endif /* NSSDEBUG */
91
92 if (arenaOpt) {
93 arena = arenaOpt;
94 i_alloced = PR_FALSE0;
95 } else {
96 arena = nssArena_Create();
97 i_alloced = PR_TRUE1;
98 }
99
100 rv = nss_ZNEW(arena, nssHash)((nssHash *)nss_ZAlloc((arena), sizeof(nssHash)));
101 if ((nssHash *)NULL((void*)0) == rv) {
102 goto loser;
103 }
104
105 rv->mutex = PZ_NewLock(nssILockOther)PR_NewLock();
106 if ((PZLockPRLock *)NULL((void*)0) == rv->mutex) {
107 goto loser;
108 }
109
110 rv->plHashTable =
111 PL_NewHashTable(numBuckets, keyHash, keyCompare, valueCompare,
112 &nssArenaHashAllocOps, arena);
113 if ((PLHashTable *)NULL((void*)0) == rv->plHashTable) {
114 (void)PZ_DestroyLock(rv->mutex)PR_DestroyLock((rv->mutex));
115 goto loser;
116 }
117
118 rv->count = 0;
119 rv->arena = arena;
120 rv->i_alloced_arena = i_alloced;
121
122 return rv;
123loser:
124 (void)nss_ZFreeIf(rv);
125 return (nssHash *)NULL((void*)0);
126}
127
128/*
129 * nssHash_CreatePointer
130 *
131 */
132NSS_IMPLEMENT nssHash *
133nssHash_CreatePointer(NSSArena *arenaOpt, PRUint32 numBuckets)
134{
135 return nssHash_Create(arenaOpt, numBuckets, nss_identity_hash,
136 PL_CompareValues, PL_CompareValues);
137}
138
139/*
140 * nssHash_CreateString
141 *
142 */
143NSS_IMPLEMENT nssHash *
144nssHash_CreateString(NSSArena *arenaOpt, PRUint32 numBuckets)
145{
146 return nssHash_Create(arenaOpt, numBuckets, PL_HashString,
147 PL_CompareStrings, PL_CompareStrings);
148}
149
150/*
151 * nssHash_CreateItem
152 *
153 */
154NSS_IMPLEMENT nssHash *
155nssHash_CreateItem(NSSArena *arenaOpt, PRUint32 numBuckets)
156{
157 return nssHash_Create(arenaOpt, numBuckets, nss_item_hash,
158 nss_compare_items, PL_CompareValues);
159}
160
161/*
162 * nssHash_Destroy
163 *
164 */
165NSS_IMPLEMENT void
166nssHash_Destroy(nssHash *hash)
167{
168 (void)PZ_DestroyLock(hash->mutex)PR_DestroyLock((hash->mutex));
169 PL_HashTableDestroy(hash->plHashTable);
170 if (hash->i_alloced_arena) {
171 nssArena_Destroy(hash->arena);
172 } else {
173 nss_ZFreeIf(hash);
174 }
175}
176
177/*
178 * nssHash_Add
179 *
180 */
181NSS_IMPLEMENT PRStatus
182nssHash_Add(nssHash *hash, const void *key, const void *value)
183{
184 PRStatus error = PR_FAILURE;
185 PLHashEntry *he;
186
187 PZ_Lock(hash->mutex)PR_Lock((hash->mutex));
188
189 he = PL_HashTableAdd(hash->plHashTable, key, (void *)value);
190 if ((PLHashEntry *)NULL((void*)0) == he) {
191 nss_SetError(NSS_ERROR_NO_MEMORY);
192 } else if (he->value != value) {
193 nss_SetError(NSS_ERROR_HASH_COLLISION);
194 } else {
195 hash->count++;
196 error = PR_SUCCESS;
197 }
198
199 (void)PZ_Unlock(hash->mutex)PR_Unlock((hash->mutex));
200
201 return error;
202}
203
204/*
205 * nssHash_Remove
206 *
207 */
208NSS_IMPLEMENT void
209nssHash_Remove(nssHash *hash, const void *it)
210{
211 PRBool found;
212
213 PZ_Lock(hash->mutex)PR_Lock((hash->mutex));
214
215 found = PL_HashTableRemove(hash->plHashTable, it);
216 if (found) {
217 hash->count--;
218 }
219
220 (void)PZ_Unlock(hash->mutex)PR_Unlock((hash->mutex));
221 return;
222}
223
224/*
225 * nssHash_Count
226 *
227 */
228NSS_IMPLEMENT PRUint32
229nssHash_Count(nssHash *hash)
230{
231 PRUint32 count;
232
233 PZ_Lock(hash->mutex)PR_Lock((hash->mutex));
234
235 count = hash->count;
236
237 (void)PZ_Unlock(hash->mutex)PR_Unlock((hash->mutex));
238
239 return count;
240}
241
242/*
243 * nssHash_Exists
244 *
245 */
246NSS_IMPLEMENT PRBool
247nssHash_Exists(nssHash *hash, const void *it)
248{
249 void *value;
250
251 PZ_Lock(hash->mutex)PR_Lock((hash->mutex));
252
253 value = PL_HashTableLookup(hash->plHashTable, it);
254
255 (void)PZ_Unlock(hash->mutex)PR_Unlock((hash->mutex));
256
257 if ((void *)NULL((void*)0) == value) {
258 return PR_FALSE0;
259 } else {
260 return PR_TRUE1;
261 }
262}
263
264/*
265 * nssHash_Lookup
266 *
267 */
268NSS_IMPLEMENT void *
269nssHash_Lookup(nssHash *hash, const void *it)
270{
271 void *rv;
272
273 PZ_Lock(hash->mutex)PR_Lock((hash->mutex));
274
275 rv = PL_HashTableLookup(hash->plHashTable, it);
276
277 (void)PZ_Unlock(hash->mutex)PR_Unlock((hash->mutex));
278
279 return rv;
280}
281
282struct arg_str {
283 nssHashIterator fcn;
284 void *closure;
285};
286
287static PRIntn
288nss_hash_enumerator(PLHashEntry *he, PRIntn index, void *arg)
289{
290 struct arg_str *as = (struct arg_str *)arg;
291 as->fcn(he->key, he->value, as->closure);
292 return HT_ENUMERATE_NEXT0;
293}
294
295/*
296 * nssHash_Iterate
297 *
298 * NOTE that the iteration function will be called with the hashtable locked.
299 */
300NSS_IMPLEMENT void
301nssHash_Iterate(nssHash *hash, nssHashIterator fcn, void *closure)
302{
303 struct arg_str as;
304 as.fcn = fcn;
305 as.closure = closure;
306
307 PZ_Lock(hash->mutex)PR_Lock((hash->mutex));
308
309 PL_HashTableEnumerateEntries(hash->plHashTable, nss_hash_enumerator, &as);
310
311 (void)PZ_Unlock(hash->mutex)PR_Unlock((hash->mutex));
312
313 return;
314}