Bug Summary

File:root/firefox-clang/security/nss/lib/smime/cmsudf.c
Warning:line 82, 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 cmsudf.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/smime/smime_smime -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/security/nss/lib/smime/smime_smime -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/smime -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/security/nss/lib/smime/smime_smime -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/smime/cmsudf.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 * CMS User Define Types
7 */
8
9#include "cmslocal.h"
10
11#include "prinit.h"
12#include "pk11func.h"
13#include "secitem.h"
14#include "secoid.h"
15#include "secerr.h"
16#include "nss.h"
17
18typedef struct nsscmstypeInfoStr nsscmstypeInfo;
19struct nsscmstypeInfoStr {
20 SECOidTag type;
21 SEC_ASN1Template *template;
22 size_t size;
23 PRBool isData;
24 NSSCMSGenericWrapperDataDestroy destroy;
25 NSSCMSGenericWrapperDataCallback decode_before;
26 NSSCMSGenericWrapperDataCallback decode_after;
27 NSSCMSGenericWrapperDataCallback decode_end;
28 NSSCMSGenericWrapperDataCallback encode_start;
29 NSSCMSGenericWrapperDataCallback encode_before;
30 NSSCMSGenericWrapperDataCallback encode_after;
31};
32
33/* make sure the global tables are only initialized once */
34static PRCallOnceType nsscmstypeOnce;
35static PRCallOnceType nsscmstypeClearOnce;
36/* lock for adding a new entry */
37static PRLock *nsscmstypeAddLock;
38/* lock for the hash table */
39static PRLock *nsscmstypeHashLock;
40/* the hash table itself */
41static PLHashTable *nsscmstypeHash;
42/* arena to hold all the hash table data */
43static PLArenaPool *nsscmstypeArena;
44
45/*
46 * clean up our global tables
47 */
48SECStatus
49nss_cmstype_shutdown(void *appData, void *reserved)
50{
51 if (nsscmstypeHashLock) {
52 PR_Lock(nsscmstypeHashLock);
53 }
54 if (nsscmstypeHash) {
55 PL_HashTableDestroy(nsscmstypeHash);
56 nsscmstypeHash = NULL((void*)0);
57 }
58 if (nsscmstypeArena) {
59 PORT_FreeArenaPORT_FreeArena_Util(nsscmstypeArena, PR_FALSE0);
60 nsscmstypeArena = NULL((void*)0);
61 }
62 if (nsscmstypeAddLock) {
63 PR_DestroyLock(nsscmstypeAddLock);
64 }
65 if (nsscmstypeHashLock) {
66 PRLock *oldLock = nsscmstypeHashLock;
67 nsscmstypeHashLock = NULL((void*)0);
68 PR_Unlock(oldLock);
69 PR_DestroyLock(oldLock);
70 }
71
72 /* don't clear out the PR_ONCE data if we failed our inital call */
73 if (appData == NULL((void*)0)) {
74 nsscmstypeOnce = nsscmstypeClearOnce;
75 }
76 return SECSuccess;
77}
78
79static PLHashNumber
80nss_cmstype_hash_key(const void *key)
81{
82 return (PLHashNumber)((char *)key - (char *)NULL((void*)0));
2
Subtraction of a probably non-null pointer and a null pointer may result in undefined behavior
83}
84
85static PRIntn
86nss_cmstype_compare_keys(const void *v1, const void *v2)
87{
88 PLHashNumber value1 = nss_cmstype_hash_key(v1);
1
Calling 'nss_cmstype_hash_key'
89 PLHashNumber value2 = nss_cmstype_hash_key(v2);
90
91 return (value1 == value2);
92}
93
94/*
95 * initialize our hash tables, called once on the first attemat to register
96 * a new SMIME type.
97 */
98static PRStatus
99nss_cmstype_init(void)
100{
101 SECStatus rv;
102
103 nsscmstypeHashLock = PR_NewLock();
104 if (nsscmstypeHashLock == NULL((void*)0)) {
105 return PR_FAILURE;
106 }
107 nsscmstypeAddLock = PR_NewLock();
108 if (nsscmstypeHashLock == NULL((void*)0)) {
109 goto fail;
110 }
111 nsscmstypeHash = PL_NewHashTable(64, nss_cmstype_hash_key,
112 nss_cmstype_compare_keys,
113 PL_CompareValues, NULL((void*)0), NULL((void*)0));
114 if (nsscmstypeHash == NULL((void*)0)) {
115 goto fail;
116 }
117 nsscmstypeArena = PORT_NewArenaPORT_NewArena_Util(2048);
118 if (nsscmstypeArena == NULL((void*)0)) {
119 goto fail;
120 }
121 rv = NSS_RegisterShutdown(nss_cmstype_shutdown, NULL((void*)0));
122 if (rv != SECSuccess) {
123 goto fail;
124 }
125 return PR_SUCCESS;
126
127fail:
128 nss_cmstype_shutdown(&nsscmstypeOnce, NULL((void*)0));
129 return PR_FAILURE;
130}
131
132/*
133 * look up and registered SIME type
134 */
135static const nsscmstypeInfo *
136nss_cmstype_lookup(SECOidTag type)
137{
138 nsscmstypeInfo *typeInfo = NULL((void*)0);
139 ;
140 if (!nsscmstypeHash) {
141 return NULL((void*)0);
142 }
143 PR_Lock(nsscmstypeHashLock);
144 if (nsscmstypeHash) {
145 typeInfo = PL_HashTableLookupConst(nsscmstypeHash, (void *)type);
146 }
147 PR_Unlock(nsscmstypeHashLock);
148 return typeInfo;
149}
150
151/*
152 * add a new type to the SMIME type table
153 */
154static SECStatus
155nss_cmstype_add(SECOidTag type, nsscmstypeInfo *typeinfo)
156{
157 PLHashEntry *entry;
158
159 if (!nsscmstypeHash) {
160 /* assert? this shouldn't happen */
161 return SECFailure;
162 }
163 PR_Lock(nsscmstypeHashLock);
164 /* this is really paranoia. If we really are racing nsscmstypeHash, we'll
165 * also be racing nsscmstypeHashLock... */
166 if (!nsscmstypeHash) {
167 PR_Unlock(nsscmstypeHashLock);
168 return SECFailure;
169 }
170 entry = PL_HashTableAdd(nsscmstypeHash, (void *)type, typeinfo);
171 PR_Unlock(nsscmstypeHashLock);
172 return entry ? SECSuccess : SECFailure;
173}
174
175/* helper functions to manage new content types
176 */
177
178PRBool
179NSS_CMSType_IsWrapper(SECOidTag type)
180{
181 const nsscmstypeInfo *typeInfo = NULL((void*)0);
182
183 switch (type) {
184 case SEC_OID_PKCS7_SIGNED_DATA:
185 case SEC_OID_PKCS7_ENVELOPED_DATA:
186 case SEC_OID_PKCS7_DIGESTED_DATA:
187 case SEC_OID_PKCS7_ENCRYPTED_DATA:
188 return PR_TRUE1;
189 default:
190 typeInfo = nss_cmstype_lookup(type);
191 if (typeInfo && !typeInfo->isData) {
192 return PR_TRUE1;
193 }
194 }
195 return PR_FALSE0;
196}
197
198PRBool
199NSS_CMSType_IsData(SECOidTag type)
200{
201 const nsscmstypeInfo *typeInfo = NULL((void*)0);
202
203 switch (type) {
204 case SEC_OID_PKCS7_DATA:
205 return PR_TRUE1;
206 default:
207 typeInfo = nss_cmstype_lookup(type);
208 if (typeInfo && typeInfo->isData) {
209 return PR_TRUE1;
210 }
211 }
212 return PR_FALSE0;
213}
214
215const SEC_ASN1Template *
216NSS_CMSType_GetTemplate(SECOidTag type)
217{
218 const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
219
220 if (typeInfo && typeInfo->template) {
221 return typeInfo->template;
222 }
223 return SEC_ASN1_GET(SEC_PointerToOctetStringTemplate)SEC_PointerToOctetStringTemplate_Util;
224}
225
226size_t
227NSS_CMSType_GetContentSize(SECOidTag type)
228{
229 const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
230
231 if (typeInfo) {
232 return typeInfo->size;
233 }
234 return sizeof(SECItem *);
235}
236
237void
238NSS_CMSGenericWrapperData_Destroy(SECOidTag type, NSSCMSGenericWrapperData *gd)
239{
240 const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
241
242 if (typeInfo && (typeInfo->destroy) && (gd != NULL((void*)0))) {
243 (*typeInfo->destroy)(gd);
244 }
245}
246
247SECStatus
248NSS_CMSGenericWrapperData_Decode_BeforeData(SECOidTag type,
249 NSSCMSGenericWrapperData *gd)
250{
251 const nsscmstypeInfo *typeInfo;
252
253 /* short cut common case */
254 if (type == SEC_OID_PKCS7_DATA) {
255 return SECSuccess;
256 }
257
258 typeInfo = nss_cmstype_lookup(type);
259 if (typeInfo) {
260 if (typeInfo->decode_before) {
261 return (*typeInfo->decode_before)(gd);
262 }
263 /* decoder ops optional for data tags */
264 if (typeInfo->isData) {
265 return SECSuccess;
266 }
267 }
268 /* expected a function, but none existed */
269 return SECFailure;
270}
271
272SECStatus
273NSS_CMSGenericWrapperData_Decode_AfterData(SECOidTag type,
274 NSSCMSGenericWrapperData *gd)
275{
276 const nsscmstypeInfo *typeInfo;
277
278 /* short cut common case */
279 if (type == SEC_OID_PKCS7_DATA) {
280 return SECSuccess;
281 }
282
283 typeInfo = nss_cmstype_lookup(type);
284 if (typeInfo) {
285 if (typeInfo->decode_after) {
286 return (*typeInfo->decode_after)(gd);
287 }
288 /* decoder ops optional for data tags */
289 if (typeInfo->isData) {
290 return SECSuccess;
291 }
292 }
293 /* expected a function, but none existed */
294 return SECFailure;
295}
296
297SECStatus
298NSS_CMSGenericWrapperData_Decode_AfterEnd(SECOidTag type,
299 NSSCMSGenericWrapperData *gd)
300{
301 const nsscmstypeInfo *typeInfo;
302
303 /* short cut common case */
304 if (type == SEC_OID_PKCS7_DATA) {
305 return SECSuccess;
306 }
307
308 typeInfo = nss_cmstype_lookup(type);
309 if (typeInfo) {
310 if (typeInfo->decode_end) {
311 return (*typeInfo->decode_end)(gd);
312 }
313 /* decoder ops optional for data tags */
314 if (typeInfo->isData) {
315 return SECSuccess;
316 }
317 }
318 /* expected a function, but none existed */
319 return SECFailure;
320}
321
322SECStatus
323NSS_CMSGenericWrapperData_Encode_BeforeStart(SECOidTag type,
324 NSSCMSGenericWrapperData *gd)
325{
326 const nsscmstypeInfo *typeInfo;
327
328 /* short cut common case */
329 if (type == SEC_OID_PKCS7_DATA) {
330 return SECSuccess;
331 }
332
333 typeInfo = nss_cmstype_lookup(type);
334 if (typeInfo) {
335 if (typeInfo->encode_start) {
336 return (*typeInfo->encode_start)(gd);
337 }
338 /* decoder ops optional for data tags */
339 if (typeInfo->isData) {
340 return SECSuccess;
341 }
342 }
343 /* expected a function, but none existed */
344 return SECFailure;
345}
346
347SECStatus
348NSS_CMSGenericWrapperData_Encode_BeforeData(SECOidTag type,
349 NSSCMSGenericWrapperData *gd)
350{
351 const nsscmstypeInfo *typeInfo;
352
353 /* short cut common case */
354 if (type == SEC_OID_PKCS7_DATA) {
355 return SECSuccess;
356 }
357
358 typeInfo = nss_cmstype_lookup(type);
359 if (typeInfo) {
360 if (typeInfo->encode_before) {
361 return (*typeInfo->encode_before)(gd);
362 }
363 /* decoder ops optional for data tags */
364 if (typeInfo->isData) {
365 return SECSuccess;
366 }
367 }
368 /* expected a function, but none existed */
369 return SECFailure;
370}
371
372SECStatus
373NSS_CMSGenericWrapperData_Encode_AfterData(SECOidTag type,
374 NSSCMSGenericWrapperData *gd)
375{
376 const nsscmstypeInfo *typeInfo;
377
378 /* short cut common case */
379 if (type == SEC_OID_PKCS7_DATA) {
380 return SECSuccess;
381 }
382
383 typeInfo = nss_cmstype_lookup(type);
384 if (typeInfo) {
385 if (typeInfo->encode_after) {
386 return (*typeInfo->encode_after)(gd);
387 }
388 /* decoder ops optional for data tags */
389 if (typeInfo->isData) {
390 return SECSuccess;
391 }
392 }
393 /* expected a function, but none existed */
394 return SECFailure;
395}
396
397SECStatus
398NSS_CMSType_RegisterContentType(SECOidTag type,
399 SEC_ASN1Template *asn1Template, size_t size,
400 NSSCMSGenericWrapperDataDestroy destroy,
401 NSSCMSGenericWrapperDataCallback decode_before,
402 NSSCMSGenericWrapperDataCallback decode_after,
403 NSSCMSGenericWrapperDataCallback decode_end,
404 NSSCMSGenericWrapperDataCallback encode_start,
405 NSSCMSGenericWrapperDataCallback encode_before,
406 NSSCMSGenericWrapperDataCallback encode_after,
407 PRBool isData)
408{
409 PRStatus rc;
410 SECStatus rv;
411 nsscmstypeInfo *typeInfo;
412 const nsscmstypeInfo *exists;
413
414 rc = PR_CallOnce(&nsscmstypeOnce, nss_cmstype_init);
415 if (rc == PR_FAILURE) {
416 return SECFailure;
417 }
418 PR_Lock(nsscmstypeAddLock);
419 exists = nss_cmstype_lookup(type);
420 if (exists) {
421 PR_Unlock(nsscmstypeAddLock);
422 /* already added */
423 return SECSuccess;
424 }
425 typeInfo = PORT_ArenaNew(nsscmstypeArena, nsscmstypeInfo)(nsscmstypeInfo *)PORT_ArenaAlloc_Util(nsscmstypeArena, sizeof
(nsscmstypeInfo))
;
426 typeInfo->type = type;
427 typeInfo->size = size;
428 typeInfo->isData = isData;
429 typeInfo->template = asn1Template;
430 typeInfo->destroy = destroy;
431 typeInfo->decode_before = decode_before;
432 typeInfo->decode_after = decode_after;
433 typeInfo->decode_end = decode_end;
434 typeInfo->encode_start = encode_start;
435 typeInfo->encode_before = encode_before;
436 typeInfo->encode_after = encode_after;
437 rv = nss_cmstype_add(type, typeInfo);
438 PR_Unlock(nsscmstypeAddLock);
439 return rv;
440}