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  * pkix_pl_object.c
6  *
7  * Object Construction, Destruction and Callback Functions
8  *
9  */
10 
11 #include "pkix_pl_object.h"
12 
13 #ifdef PKIX_USER_OBJECT_TYPE
14 /* --Class-Table-Initializers------------------------------------ */
15 
16 /*
17  * Create storage space for 20 Class Table buckets.
18  * These are only for user-defined types. System types are registered
19  * separately by PKIX_PL_Initialize.
20  */
21 
22 static pkix_pl_HT_Elem*
23 pkix_Raw_ClassTable_Buckets[] = {
24         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
25         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
26 };
27 
28 /*
29  * Allocate static memory for a ClassTable.
30  * XXX This assumes the bucket pointer will fit into a PKIX_UInt32
31  */
32 static pkix_pl_PrimHashTable pkix_Raw_ClassTable = {
33         (void *)pkix_Raw_ClassTable_Buckets, /* Buckets */
34         20 /* Number of Buckets */
35 };
36 static pkix_pl_PrimHashTable * classTable = &pkix_Raw_ClassTable;
37 #endif /* PKIX_USER_OBJECT_TYPE */
38 
39 /* --Private-Functions-------------------------------------------- */
40 
41 /*
42  * FUNCTION: pkix_pl_Object_GetHeader
43  * DESCRIPTION:
44  *
45  *  Shifts Object pointed to by "object" by the sizeof(PKIX_PL_Object) and
46  *  stores the value at "pObjectHeader".
47  *
48  * PARAMETERS:
49  *  "object"
50  *      Address of Object to shift. Must be non-NULL.
51  *  "pObjectHeader"
52  *      Address where object pointer will be stored. Must be non-NULL.
53  *  "plContext"
54  *      Platform-specific context pointer.
55  * THREAD SAFETY:
56  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
57  * RETURNS:
58  *  Returns NULL if the function succeeds.
59  *  Returns a Fatal Error if the function fails in an unrecoverable way.
60  */
61 static PKIX_Error *
pkix_pl_Object_GetHeader(PKIX_PL_Object * object,PKIX_PL_Object ** pObjectHeader,void * plContext)62 pkix_pl_Object_GetHeader(
63         PKIX_PL_Object *object,
64         PKIX_PL_Object **pObjectHeader,
65         void *plContext)
66 {
67         PKIX_PL_Object *header = NULL;
68         PKIX_UInt32 objType;
69 
70         PKIX_ENTER(OBJECT, "pkix_pl_Object_GetHeader");
71         PKIX_NULLCHECK_TWO(object, pObjectHeader);
72 
73         PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
74 
75         /* The header is sizeof(PKIX_PL_Object) before the object pointer */
76         header = (PKIX_PL_Object *)((char *)object - sizeof(PKIX_PL_Object));
77 
78         objType = header->type;
79 
80         if (objType >= PKIX_NUMTYPES) { /* if this is a user-defined type */
81 #ifdef PKIX_USER_OBJECT_TYPE
82                 pkix_ClassTable_Entry *ctEntry = NULL;
83 
84                 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
85                 PR_Lock(classTableLock);
86 
87                 PKIX_CHECK(pkix_pl_PrimHashTable_Lookup
88                             (classTable,
89                             (void *)&objType,
90                             objType,
91                             NULL,
92                             (void **)&ctEntry,
93                             plContext),
94                             PKIX_ERRORGETTINGCLASSTABLEENTRY);
95 
96                 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
97                 PR_Unlock(classTableLock);
98 
99                 if (ctEntry == NULL) {
100                         PKIX_ERROR_FATAL(PKIX_UNKNOWNOBJECTTYPE);
101                 }
102 #else
103                 PORT_Assert(objType < PKIX_NUMTYPES);
104                 pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
105                 pkixErrorClass = PKIX_FATAL_ERROR;
106                 goto cleanup;
107 #endif /* PKIX_USER_OBJECT_TYPE */
108         }
109 
110 #ifdef PKIX_OBJECT_LEAK_TEST
111         PORT_Assert(header && header->magicHeader == PKIX_MAGIC_HEADER);
112 #endif /* PKIX_OBJECT_LEAK_TEST */
113 
114         if ((header == NULL)||
115             (header->magicHeader != PKIX_MAGIC_HEADER)) {
116                 PKIX_ERROR_ALLOC_ERROR();
117         }
118 
119         *pObjectHeader = header;
120 
121 cleanup:
122 
123         PKIX_RETURN(OBJECT);
124 }
125 
126 /*
127  * FUNCTION: pkix_Destroy_Object
128  * DESCRIPTION:
129  *
130  *  Destroys and deallocates Object pointed to by "object". The caller is
131  *  assumed to hold the Object's lock, which is acquired in
132  *  PKIX_PL_Object_DecRef().
133  *
134  * PARAMETERS:
135  *  "object"
136  *      Address of Object to destroy. Must be non-NULL.
137  *  "plContext"
138  *      Platform-specific context pointer.
139  * THREAD SAFETY:
140  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
141  * RETURNS:
142  *  Returns NULL if the function succeeds.
143  *  Returns a Fatal Error if the function fails in an unrecoverable way.
144  */
145 static PKIX_Error *
pkix_pl_Object_Destroy(PKIX_PL_Object * object,void * plContext)146 pkix_pl_Object_Destroy(
147         PKIX_PL_Object *object,
148         void *plContext)
149 {
150         PKIX_PL_Object *objectHeader = NULL;
151 
152         PKIX_ENTER(OBJECT, "pkix_pl_Object_Destroy");
153         PKIX_NULLCHECK_ONE(object);
154 
155 #ifdef PKIX_OBJECT_LEAK_TEST
156         PKIX_CHECK_FATAL(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
157                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
158 #else
159         PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
160                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
161 #endif /* PKIX_OBJECT_LEAK_TEST */
162 
163         /* Attempt to delete an object still being used */
164         if (objectHeader->references != 0) {
165                 PKIX_ERROR_FATAL(PKIX_OBJECTSTILLREFERENCED);
166         }
167 
168         PKIX_DECREF(objectHeader->stringRep);
169 
170         /* Destroy this object's lock */
171         PKIX_OBJECT_DEBUG("\tCalling PR_DestroyLock).\n");
172         PR_DestroyLock(objectHeader->lock);
173         objectHeader->lock = NULL;
174         object = NULL;
175 
176         objectHeader->magicHeader = PKIX_MAGIC_HEADER_DESTROYED;
177 
178 #ifdef PKIX_OBJECT_LEAK_TEST
179         memset(objectHeader, 0xbf, systemClasses[PKIX_OBJECT_TYPE].typeObjectSize);
180 #endif
181 
182         PKIX_FREE(objectHeader);
183 
184 cleanup:
185 #ifdef PKIX_OBJECT_LEAK_TEST
186 fatal:
187 #endif
188 
189         PKIX_RETURN(OBJECT);
190 }
191 
192 /* --Default-Callbacks-------------------------------------------- */
193 
194 /*
195  * FUNCTION: pkix_pl_Object_Equals_Default
196  * DESCRIPTION:
197  *
198  *  Default Object_Equals callback: Compares the address of the Object pointed
199  *  to by "firstObject" with the address of the Object pointed to by
200  *  "secondObject" and stores the Boolean result at "pResult".
201  *
202  * PARAMETERS:
203  *  "firstObject"
204  *      Address of first Object to compare. Must be non-NULL.
205  *  "secondObject"
206  *      Address of second Object to compare. Must be non-NULL.
207  *  "pResult"
208  *      Address where Boolean result will be stored. Must be non-NULL.
209  *  "plContext"
210  *      Platform-specific context pointer.
211  * THREAD SAFETY:
212  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
213  * RETURNS:
214  *  Returns NULL if the function succeeds.
215  *  Returns a Fatal Error if the function fails in an unrecoverable way.
216  */
217 static PKIX_Error *
pkix_pl_Object_Equals_Default(PKIX_PL_Object * firstObject,PKIX_PL_Object * secondObject,PKIX_Boolean * pResult,void * plContext)218 pkix_pl_Object_Equals_Default(
219         PKIX_PL_Object *firstObject,
220         PKIX_PL_Object *secondObject,
221         PKIX_Boolean *pResult,
222         void *plContext)
223 {
224         PKIX_ENTER(OBJECT, "pkix_pl_Object_Equals_Default");
225         PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
226 
227         /* Just compare pointer values */
228         *pResult = (firstObject == secondObject)?PKIX_TRUE:PKIX_FALSE;
229 
230         PKIX_RETURN(OBJECT);
231 }
232 
233 /*
234  * FUNCTION: pkix_pl_Object_ToString_Default
235  * DESCRIPTION:
236  *
237  *  Default Object_ToString callback: Creates a string consisting of the
238  *  typename and address of the Object pointed to by "object" and stores
239  *  the result at "pString". The format for the string is
240  *  "TypeName@Address: <address>", where the default typename is "Object".
241  *
242  * PARAMETERS:
243  *  "object"
244  *      Address of Object to convert to a string. Must be non-NULL.
245  *  "pString"
246  *      Address where object pointer will be stored. Must be non-NULL.
247  *  "plContext"
248  *      Platform-specific context pointer.
249  * THREAD SAFETY:
250  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
251  * RETURNS:
252  *  Returns NULL if the function succeeds.
253  *  Returns an Object Error if the function fails in a non-fatal way.
254  *  Returns a Fatal Error if the function fails in an unrecoverable way.
255  */
256 static PKIX_Error *
pkix_pl_Object_ToString_Default(PKIX_PL_Object * object,PKIX_PL_String ** pString,void * plContext)257 pkix_pl_Object_ToString_Default(
258         PKIX_PL_Object *object,
259         PKIX_PL_String **pString,
260         void *plContext)
261 {
262         PKIX_PL_String *formatString = NULL;
263         PKIX_PL_String *descString = NULL;
264         char *format = "%s@Address: %x";
265         char *description = NULL;
266         PKIX_UInt32 objType;
267 
268         PKIX_ENTER(OBJECT, "pkix_pl_Object_ToString_Default");
269         PKIX_NULLCHECK_TWO(object, pString);
270 
271         PKIX_CHECK(PKIX_PL_Object_GetType(object, &objType, plContext),
272                     PKIX_OBJECTGETTYPEFAILED);
273 
274         if (objType >= PKIX_NUMTYPES){
275 #ifdef PKIX_USER_OBJECT_TYPE
276                 pkix_ClassTable_Entry *ctEntry = NULL;
277 
278                 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
279                 PR_Lock(classTableLock);
280                 pkixErrorResult = pkix_pl_PrimHashTable_Lookup
281                         (classTable,
282                         (void *)&objType,
283                         objType,
284                         NULL,
285                         (void **)&ctEntry,
286                         plContext);
287                 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
288                 PR_Unlock(classTableLock);
289                 if (pkixErrorResult){
290                         PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY);
291                 }
292 
293                 if (ctEntry == NULL){
294                         PKIX_ERROR_FATAL(PKIX_UNDEFINEDCLASSTABLEENTRY);
295                 } else {
296                         description = ctEntry->description;
297                         if (description == NULL) {
298                             description = "User Type Object";
299                         }
300                 }
301 #else
302                 PORT_Assert (0);
303                 pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
304                 pkixErrorClass = PKIX_FATAL_ERROR;
305                 goto cleanup;
306 #endif /* PKIX_USER_OBJECT_TYPE */
307         } else {
308                 description = systemClasses[objType].description;
309         }
310         PKIX_CHECK(PKIX_PL_String_Create
311                     (PKIX_ESCASCII,
312                     (void *)format,
313                     0,
314                     &formatString,
315                     plContext),
316                     PKIX_STRINGCREATEFAILED);
317 
318         PKIX_CHECK(PKIX_PL_String_Create
319                     (PKIX_ESCASCII,
320                     (void *)description,
321                     0,
322                     &descString,
323                     plContext),
324                     PKIX_STRINGCREATEFAILED);
325 
326         PKIX_CHECK(PKIX_PL_Sprintf
327                     (pString,
328                     plContext,
329                     formatString,
330                     descString,
331                     object),
332                     PKIX_SPRINTFFAILED);
333 
334 cleanup:
335 
336         PKIX_DECREF(formatString);
337         PKIX_DECREF(descString);
338 
339         PKIX_RETURN(OBJECT);
340 }
341 
342 /*
343  * FUNCTION: pkix_pl_Object_Hashcode_Default
344  * DESCRIPTION:
345  *
346  *  Default Object_Hashcode callback. Creates the a hashcode value using the
347  *  address of the Object pointed to by "object" and stores the result at
348  *  "pValue".
349  *
350  *  XXX This isn't great since addresses are not uniformly distributed.
351  *
352  * PARAMETERS:
353  *  "object"
354  *      Address of Object to compute hashcode for. Must be non-NULL.
355  *  "pValue"
356  *      Address where PKIX_UInt32 will be stored. Must be non-NULL.
357  *  "plContext"
358  *      Platform-specific context pointer.
359  * THREAD SAFETY:
360  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
361  * RETURNS:
362  *  Returns NULL if the function succeeds.
363  *  Returns a Fatal Error if the function fails in an unrecoverable way.
364  */
365 static PKIX_Error *
pkix_pl_Object_Hashcode_Default(PKIX_PL_Object * object,PKIX_UInt32 * pValue,void * plContext)366 pkix_pl_Object_Hashcode_Default(
367         PKIX_PL_Object *object,
368         PKIX_UInt32 *pValue,
369         void *plContext)
370 {
371         PKIX_ENTER(OBJECT, "pkix_pl_Object_Hashcode_Default");
372         PKIX_NULLCHECK_TWO(object, pValue);
373 
374         *pValue = (PKIX_UInt32)((char *)object - (char *)NULL);
375 
376         PKIX_RETURN(OBJECT);
377 }
378 
379 /*
380  * FUNCTION: pkix_pl_Object_RetrieveEqualsCallback
381  * DESCRIPTION:
382  *
383  *  Retrieves Equals callback function of Object pointed to by "object and
384  *  stores it at "pEqualsCallback". If the object's type is one of the system
385  *  types, its callback function is retrieved from the systemClasses array;
386  *  otherwise, its callback function is retrieve from the classTable hash
387  *  table where user-defined types are stored.
388  *
389  * PARAMETERS:
390  *  "object"
391  *      Address of Object whose equals callback is desired. Must be non-NULL.
392  *  "pEqualsCallback"
393  *      Address where EqualsCallback function pointer will be stored.
394  *      Must be non-NULL.
395  *  "plContext"
396  *      Platform-specific context pointer.
397  * THREAD SAFETY:
398  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
399  * RETURNS:
400  *  Returns NULL if the function succeeds.
401  *  Returns an Object Error if the function fails in a non-fatal way.
402  *  Returns a Fatal Error if the function fails in an unrecoverable way.
403  */
404 PKIX_Error *
pkix_pl_Object_RetrieveEqualsCallback(PKIX_PL_Object * object,PKIX_PL_EqualsCallback * pEqualsCallback,void * plContext)405 pkix_pl_Object_RetrieveEqualsCallback(
406         PKIX_PL_Object *object,
407         PKIX_PL_EqualsCallback *pEqualsCallback,
408         void *plContext)
409 {
410         PKIX_PL_Object *objectHeader = NULL;
411         PKIX_PL_EqualsCallback func = NULL;
412         pkix_ClassTable_Entry entry;
413         PKIX_UInt32 objType;
414 
415         PKIX_ENTER(OBJECT, "pkix_pl_Object_RetrieveEqualsCallback");
416         PKIX_NULLCHECK_TWO(object, pEqualsCallback);
417 
418         PKIX_CHECK(pkix_pl_Object_GetHeader
419                     (object, &objectHeader, plContext),
420                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
421 
422         objType = objectHeader->type;
423 
424         if (objType >= PKIX_NUMTYPES){
425 #ifdef PKIX_USER_OBJECT_TYPE
426                 pkix_ClassTable_Entry *ctEntry = NULL;
427 
428                 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
429                 PR_Lock(classTableLock);
430                 pkixErrorResult = pkix_pl_PrimHashTable_Lookup
431                         (classTable,
432                         (void *)&objType,
433                         objType,
434                         NULL,
435                         (void **)&ctEntry,
436                         plContext);
437                 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
438                 PR_Unlock(classTableLock);
439                 if (pkixErrorResult){
440                         PKIX_ERROR(PKIX_ERRORGETTINGCLASSTABLEENTRY);
441                 }
442 
443                 if ((ctEntry == NULL) || (ctEntry->equalsFunction == NULL)) {
444                         PKIX_ERROR(PKIX_UNDEFINEDEQUALSCALLBACK);
445                 } else {
446                         *pEqualsCallback = ctEntry->equalsFunction;
447                 }
448 #else
449                 PORT_Assert (0);
450                 pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
451                 pkixErrorClass = PKIX_FATAL_ERROR;
452                 goto cleanup;
453 #endif /* PKIX_USER_OBJECT_TYPE */
454         } else {
455                 entry = systemClasses[objType];
456                 func = entry.equalsFunction;
457                 if (func == NULL){
458                         func = pkix_pl_Object_Equals_Default;
459                 }
460                 *pEqualsCallback = func;
461         }
462 
463 cleanup:
464 
465         PKIX_RETURN(OBJECT);
466 }
467 
468 /*
469  * FUNCTION: pkix_pl_Object_RegisterSelf
470  * DESCRIPTION:
471  *  Registers PKIX_OBJECT_TYPE and its related functions with systemClasses[]
472  * THREAD SAFETY:
473  *  Not Thread Safe - for performance and complexity reasons
474  *
475  *  Since this function is only called by PKIX_PL_Initialize, which should
476  *  only be called once, it is acceptable that this function is not
477  *  thread-safe.
478  *
479  *  PKIX_PL_Object should have all function pointes to be to NULL: they
480  *  work as proxy function to a real objects.
481  *
482  */
483 PKIX_Error *
pkix_pl_Object_RegisterSelf(void * plContext)484 pkix_pl_Object_RegisterSelf(void *plContext)
485 {
486         pkix_ClassTable_Entry entry;
487 
488         PKIX_ENTER(ERROR, "pkix_pl_Object_RegisterSelf");
489 
490         entry.description = "Object";
491         entry.objCounter = 0;
492         entry.typeObjectSize = sizeof(PKIX_PL_Object);
493         entry.destructor = NULL;
494         entry.equalsFunction = NULL;
495         entry.hashcodeFunction = NULL;
496         entry.toStringFunction = NULL;
497         entry.comparator = NULL;
498         entry.duplicateFunction = NULL;
499 
500         systemClasses[PKIX_OBJECT_TYPE] = entry;
501 
502         PKIX_RETURN(ERROR);
503 }
504 
505 /* --Public-Functions------------------------------------------------------- */
506 
507 /*
508  * FUNCTION: PKIX_PL_Object_Alloc (see comments in pkix_pl_system.h)
509  */
510 PKIX_Error *
PKIX_PL_Object_Alloc(PKIX_TYPENUM objType,PKIX_UInt32 size,PKIX_PL_Object ** pObject,void * plContext)511 PKIX_PL_Object_Alloc(
512         PKIX_TYPENUM objType,
513         PKIX_UInt32 size,
514         PKIX_PL_Object **pObject,
515         void *plContext)
516 {
517         PKIX_PL_Object *object = NULL;
518         pkix_ClassTable_Entry *ctEntry = NULL;
519 
520         PKIX_ENTER(OBJECT, "PKIX_PL_Object_Alloc");
521         PKIX_NULLCHECK_ONE(pObject);
522 
523         /*
524          * We need to ensure that user-defined types have been registered.
525          * All system types have already been registered by PKIX_PL_Initialize.
526          */
527 
528         if (objType >= PKIX_NUMTYPES) { /* i.e. if this is a user-defined type */
529 #ifdef PKIX_USER_OBJECT_TYPE
530                 PKIX_Boolean typeRegistered;
531                 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
532                 PR_Lock(classTableLock);
533                 pkixErrorResult = pkix_pl_PrimHashTable_Lookup
534                         (classTable,
535                         (void *)&objType,
536                         objType,
537                         NULL,
538                         (void **)&ctEntry,
539                         plContext);
540                 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
541                 PR_Unlock(classTableLock);
542                 if (pkixErrorResult){
543                         PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE);
544                 }
545 
546                 typeRegistered = (ctEntry != NULL);
547 
548                 if (!typeRegistered) {
549                         PKIX_ERROR_FATAL(PKIX_UNKNOWNTYPEARGUMENT);
550                 }
551 #else
552                 PORT_Assert (0);
553                 pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
554                 pkixErrorClass = PKIX_FATAL_ERROR;
555                 goto cleanup;
556 #endif /* PKIX_USER_OBJECT_TYPE */
557         } else {
558                 ctEntry = &systemClasses[objType];
559         }
560 
561         PORT_Assert(size == ctEntry->typeObjectSize);
562 
563         /* Allocate space for the object header and the requested size */
564 #ifdef PKIX_OBJECT_LEAK_TEST
565         PKIX_CHECK(PKIX_PL_Calloc
566                     (1,
567                     ((PKIX_UInt32)sizeof (PKIX_PL_Object))+size,
568                     (void **)&object,
569                     plContext),
570                     PKIX_MALLOCFAILED);
571 #else
572         PKIX_CHECK(PKIX_PL_Malloc
573                     (((PKIX_UInt32)sizeof (PKIX_PL_Object))+size,
574                     (void **)&object,
575                     plContext),
576                     PKIX_MALLOCFAILED);
577 #endif /* PKIX_OBJECT_LEAK_TEST */
578 
579         /* Initialize all object fields */
580         object->magicHeader = PKIX_MAGIC_HEADER;
581         object->type = objType;
582         object->references = 1; /* Default to a single reference */
583         object->stringRep = NULL;
584         object->hashcode = 0;
585         object->hashcodeCached = 0;
586 
587         /* Cannot use PKIX_PL_Mutex because it depends on Object */
588         /* Using NSPR Locks instead */
589         PKIX_OBJECT_DEBUG("\tCalling PR_NewLock).\n");
590         object->lock = PR_NewLock();
591         if (object->lock == NULL) {
592                 PKIX_ERROR_ALLOC_ERROR();
593         }
594 
595         PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
596 
597 
598         /* Return a pointer to the user data. Need to offset by object size */
599         *pObject = object + 1;
600         object = NULL;
601 
602         /* Atomically increment object counter */
603         PR_ATOMIC_INCREMENT((PRInt32*)&ctEntry->objCounter);
604 
605 cleanup:
606 
607         PKIX_FREE(object);
608 
609         PKIX_RETURN(OBJECT);
610 }
611 
612 /*
613  * FUNCTION: PKIX_PL_Object_IsTypeRegistered (see comments in pkix_pl_system.h)
614  */
615 PKIX_Error *
PKIX_PL_Object_IsTypeRegistered(PKIX_UInt32 objType,PKIX_Boolean * pBool,void * plContext)616 PKIX_PL_Object_IsTypeRegistered(
617         PKIX_UInt32 objType,
618         PKIX_Boolean *pBool,
619         void *plContext)
620 {
621 #ifdef PKIX_USER_OBJECT_TYPE
622         pkix_ClassTable_Entry *ctEntry = NULL;
623 #endif
624 
625         PKIX_ENTER(OBJECT, "PKIX_PL_Object_IsTypeRegistered");
626         PKIX_NULLCHECK_ONE(pBool);
627 
628         /* first, we handle the system types */
629         if (objType < PKIX_NUMTYPES) {
630                 *pBool = PKIX_TRUE;
631                 goto cleanup;
632         }
633 
634 #ifndef PKIX_USER_OBJECT_TYPE
635         PORT_Assert (0);
636         pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
637         pkixErrorClass = PKIX_FATAL_ERROR;
638 #else
639         PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
640         PR_Lock(classTableLock);
641         pkixErrorResult = pkix_pl_PrimHashTable_Lookup
642                 (classTable,
643                 (void *)&objType,
644                 objType,
645                 NULL,
646                 (void **)&ctEntry,
647                 plContext);
648         PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
649         PR_Unlock(classTableLock);
650 
651         if (pkixErrorResult){
652                 PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE);
653         }
654 
655         *pBool = (ctEntry != NULL);
656 #endif /* PKIX_USER_OBJECT_TYPE */
657 
658 cleanup:
659 
660         PKIX_RETURN(OBJECT);
661 }
662 
663 #ifdef PKIX_USER_OBJECT_TYPE
664 /*
665  * FUNCTION: PKIX_PL_Object_RegisterType (see comments in pkix_pl_system.h)
666  */
667 PKIX_Error *
PKIX_PL_Object_RegisterType(PKIX_UInt32 objType,char * description,PKIX_PL_DestructorCallback destructor,PKIX_PL_EqualsCallback equalsFunction,PKIX_PL_HashcodeCallback hashcodeFunction,PKIX_PL_ToStringCallback toStringFunction,PKIX_PL_ComparatorCallback comparator,PKIX_PL_DuplicateCallback duplicateFunction,void * plContext)668 PKIX_PL_Object_RegisterType(
669         PKIX_UInt32 objType,
670         char *description,
671         PKIX_PL_DestructorCallback destructor,
672         PKIX_PL_EqualsCallback equalsFunction,
673         PKIX_PL_HashcodeCallback hashcodeFunction,
674         PKIX_PL_ToStringCallback toStringFunction,
675         PKIX_PL_ComparatorCallback comparator,
676         PKIX_PL_DuplicateCallback duplicateFunction,
677         void *plContext)
678 {
679         pkix_ClassTable_Entry *ctEntry = NULL;
680         pkix_pl_Integer *key = NULL;
681 
682         PKIX_ENTER(OBJECT, "PKIX_PL_Object_RegisterType");
683 
684         /*
685          * System types are registered on startup by PKIX_PL_Initialize.
686          * These can not be overwritten.
687          */
688 
689         if (objType < PKIX_NUMTYPES) { /* if this is a system type */
690                 PKIX_ERROR(PKIX_CANTREREGISTERSYSTEMTYPE);
691         }
692 
693         PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
694         PR_Lock(classTableLock);
695         PKIX_CHECK(pkix_pl_PrimHashTable_Lookup
696                     (classTable,
697                     (void *)&objType,
698                     objType,
699                     NULL,
700                     (void **)&ctEntry,
701                     plContext),
702                     PKIX_PRIMHASHTABLELOOKUPFAILED);
703 
704         /* If the type is already registered, throw an error */
705         if (ctEntry) {
706                 PKIX_ERROR(PKIX_TYPEALREADYREGISTERED);
707         }
708 
709         PKIX_CHECK(PKIX_PL_Malloc
710                     (((PKIX_UInt32)sizeof (pkix_ClassTable_Entry)),
711                     (void **)&ctEntry,
712                     plContext),
713                     PKIX_MALLOCFAILED);
714 
715         /* Set Default Values if none specified */
716 
717         if (description == NULL){
718                 description = "Object";
719         }
720 
721         if (equalsFunction == NULL) {
722                 equalsFunction = pkix_pl_Object_Equals_Default;
723         }
724 
725         if (toStringFunction == NULL) {
726                 toStringFunction = pkix_pl_Object_ToString_Default;
727         }
728 
729         if (hashcodeFunction == NULL) {
730                 hashcodeFunction = pkix_pl_Object_Hashcode_Default;
731         }
732 
733         ctEntry->destructor = destructor;
734         ctEntry->equalsFunction = equalsFunction;
735         ctEntry->toStringFunction = toStringFunction;
736         ctEntry->hashcodeFunction = hashcodeFunction;
737         ctEntry->comparator = comparator;
738         ctEntry->duplicateFunction = duplicateFunction;
739         ctEntry->description = description;
740 
741         PKIX_CHECK(PKIX_PL_Malloc
742                     (((PKIX_UInt32)sizeof (pkix_pl_Integer)),
743                     (void **)&key,
744                     plContext),
745                     PKIX_COULDNOTMALLOCNEWKEY);
746 
747         key->ht_int = objType;
748 
749         PKIX_CHECK(pkix_pl_PrimHashTable_Add
750                     (classTable,
751                     (void *)key,
752                     (void *)ctEntry,
753                     objType,
754                     NULL,
755                     plContext),
756                     PKIX_PRIMHASHTABLEADDFAILED);
757 
758 cleanup:
759         PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
760         PR_Unlock(classTableLock);
761 
762         PKIX_RETURN(OBJECT);
763 }
764 #endif /* PKIX_USER_OBJECT_TYPE */
765 
766 /*
767  * FUNCTION: PKIX_PL_Object_IncRef (see comments in pkix_pl_system.h)
768  */
769 PKIX_Error *
PKIX_PL_Object_IncRef(PKIX_PL_Object * object,void * plContext)770 PKIX_PL_Object_IncRef(
771         PKIX_PL_Object *object,
772         void *plContext)
773 {
774         PKIX_PL_Object *objectHeader = NULL;
775         PKIX_PL_NssContext *context = NULL;
776         PKIX_Int32 refCount = 0;
777 
778         PKIX_ENTER(OBJECT, "PKIX_PL_Object_IncRef");
779         PKIX_NULLCHECK_ONE(object);
780 
781         if (plContext){
782                 /*
783                  * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't
784                  * have a header therefore we cannot verify its type before
785                  * casting.
786                  */
787                 context = (PKIX_PL_NssContext *) plContext;
788                 if (context->arena != NULL) {
789                         goto cleanup;
790                 }
791         }
792 
793         if (object == (PKIX_PL_Object*)PKIX_ALLOC_ERROR()) {
794                 goto cleanup;
795         }
796 
797         /* Shift pointer from user data to object header */
798         PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
799                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
800 
801         /* This object should never have zero references */
802         refCount = PR_ATOMIC_INCREMENT(&objectHeader->references);
803 
804         if (refCount <= 1) {
805                 PKIX_THROW(FATAL, PKIX_OBJECTWITHNONPOSITIVEREFERENCES);
806         }
807 
808 cleanup:
809 
810         PKIX_RETURN(OBJECT);
811 }
812 
813 /*
814  * FUNCTION: PKIX_PL_Object_DecRef (see comments in pkix_pl_system.h)
815  */
816 PKIX_Error *
PKIX_PL_Object_DecRef(PKIX_PL_Object * object,void * plContext)817 PKIX_PL_Object_DecRef(
818         PKIX_PL_Object *object,
819         void *plContext)
820 {
821         PKIX_Int32 refCount = 0;
822         PKIX_PL_Object *objectHeader = NULL;
823         PKIX_PL_NssContext *context = NULL;
824 
825         PKIX_ENTER(OBJECT, "PKIX_PL_Object_DecRef");
826         PKIX_NULLCHECK_ONE(object);
827 
828         if (plContext){
829                 /*
830                  * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't
831                  * have a header therefore we cannot verify its type before
832                  * casting.
833                  */
834                 context = (PKIX_PL_NssContext *) plContext;
835                 if (context->arena != NULL) {
836                         goto cleanup;
837                 }
838         }
839 
840         if (object == (PKIX_PL_Object*)PKIX_ALLOC_ERROR()) {
841                 goto cleanup;
842         }
843 
844         /* Shift pointer from user data to object header */
845         PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
846                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
847 
848         refCount = PR_ATOMIC_DECREMENT(&objectHeader->references);
849 
850         if (refCount == 0) {
851             PKIX_PL_DestructorCallback destructor = NULL;
852             pkix_ClassTable_Entry *ctEntry = NULL;
853             PKIX_UInt32 objType = objectHeader->type;
854 
855             /* first, special handling for system types */
856             if (objType >= PKIX_NUMTYPES){
857 #ifdef PKIX_USER_OBJECT_TYPE
858                 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
859                 PR_Lock(classTableLock);
860                 pkixErrorResult = pkix_pl_PrimHashTable_Lookup
861                     (classTable,
862                      (void *)&objType,
863                      objType,
864                      NULL,
865                      (void **)&ctEntry,
866                      plContext);
867                 PKIX_OBJECT_DEBUG
868                     ("\tCalling PR_Unlock).\n");
869                 PR_Unlock(classTableLock);
870                 if (pkixErrorResult){
871                     PKIX_ERROR_FATAL
872                         (PKIX_ERRORINGETTINGDESTRUCTOR);
873                 }
874 
875                 if (ctEntry != NULL){
876                     destructor = ctEntry->destructor;
877                 }
878 #else
879                 PORT_Assert (0);
880                 pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
881                 pkixErrorClass = PKIX_FATAL_ERROR;
882                 goto cleanup;
883 #endif /* PKIX_USER_OBJECT_TYPE */
884             } else {
885                 ctEntry = &systemClasses[objType];
886                 destructor = ctEntry->destructor;
887             }
888 
889             if (destructor != NULL){
890                 /* Call destructor on user data if necessary */
891                 pkixErrorResult = destructor(object, plContext);
892                 if (pkixErrorResult) {
893                     pkixErrorClass = PKIX_FATAL_ERROR;
894                     PKIX_DoAddError(stdVarsPtr, pkixErrorResult, plContext);
895                     pkixErrorResult = NULL;
896                 }
897             }
898 
899             /* Atomically decrement object counter */
900             PR_ATOMIC_DECREMENT((PRInt32*)&ctEntry->objCounter);
901 
902             /* pkix_pl_Object_Destroy assumes the lock is held */
903             /* It will call unlock and destroy the object */
904             pkixErrorResult = pkix_pl_Object_Destroy(object, plContext);
905             goto cleanup;
906         }
907 
908         if (refCount < 0) {
909             PKIX_ERROR_ALLOC_ERROR();
910         }
911 
912 cleanup:
913 
914         PKIX_RETURN(OBJECT);
915 }
916 
917 
918 
919 /*
920  * FUNCTION: PKIX_PL_Object_Equals (see comments in pkix_pl_system.h)
921  */
922 PKIX_Error *
PKIX_PL_Object_Equals(PKIX_PL_Object * firstObject,PKIX_PL_Object * secondObject,PKIX_Boolean * pResult,void * plContext)923 PKIX_PL_Object_Equals(
924         PKIX_PL_Object *firstObject,
925         PKIX_PL_Object *secondObject,
926         PKIX_Boolean *pResult,
927         void *plContext)
928 {
929         PKIX_PL_Object *firstObjectHeader = NULL;
930         PKIX_PL_Object *secondObjectHeader = NULL;
931         PKIX_PL_EqualsCallback func = NULL;
932         pkix_ClassTable_Entry entry;
933         PKIX_UInt32 objType;
934 
935         PKIX_ENTER(OBJECT, "PKIX_PL_Object_Equals");
936         PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
937 
938         PKIX_CHECK(pkix_pl_Object_GetHeader
939                     (firstObject, &firstObjectHeader, plContext),
940                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
941 
942         PKIX_CHECK(pkix_pl_Object_GetHeader
943                     (secondObject, &secondObjectHeader, plContext),
944                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
945 
946         /* if hashcodes are cached but not equal, objects can't be equal */
947         if (firstObjectHeader->hashcodeCached &&
948             secondObjectHeader->hashcodeCached){
949                 if (firstObjectHeader->hashcode !=
950                     secondObjectHeader->hashcode){
951                         *pResult = PKIX_FALSE;
952                         goto cleanup;
953                 }
954         }
955 
956         objType = firstObjectHeader->type;
957 
958         if (objType >= PKIX_NUMTYPES) {
959 #ifdef PKIX_USER_OBJECT_TYPE
960                 pkix_ClassTable_Entry *ctEntry = NULL;
961                 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
962                 PR_Lock(classTableLock);
963                 pkixErrorResult = pkix_pl_PrimHashTable_Lookup
964                         (classTable,
965                         (void *)&firstObjectHeader->type,
966                         firstObjectHeader->type,
967                         NULL,
968                         (void **)&ctEntry,
969                         plContext);
970                 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
971                 PR_Unlock(classTableLock);
972 
973                 if (pkixErrorResult){
974                         PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY);
975                 }
976 
977                 if ((ctEntry == NULL) || (ctEntry->equalsFunction == NULL)) {
978                         PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK);
979                 } else {
980                         func = ctEntry->equalsFunction;
981                 }
982 #else
983                 PORT_Assert (0);
984                 pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
985                 pkixErrorClass = PKIX_FATAL_ERROR;
986                 goto cleanup;
987 #endif /* PKIX_USER_OBJECT_TYPE */
988         } else {
989                 entry = systemClasses[objType];
990                 func = entry.equalsFunction;
991                 if (func == NULL){
992                         func = pkix_pl_Object_Equals_Default;
993                 }
994         }
995 
996         PKIX_CHECK(func(firstObject, secondObject, pResult, plContext),
997                     PKIX_OBJECTSPECIFICFUNCTIONFAILED);
998 
999 cleanup:
1000 
1001         PKIX_RETURN(OBJECT);
1002 }
1003 
1004 /*
1005  * FUNCTION: PKIX_PL_Object_Duplicate (see comments in pkix_pl_system.h)
1006  */
1007 PKIX_Error *
PKIX_PL_Object_Duplicate(PKIX_PL_Object * firstObject,PKIX_PL_Object ** pNewObject,void * plContext)1008 PKIX_PL_Object_Duplicate(
1009         PKIX_PL_Object *firstObject,
1010         PKIX_PL_Object **pNewObject,
1011         void *plContext)
1012 {
1013         PKIX_PL_Object *firstObjectHeader = NULL;
1014         PKIX_PL_DuplicateCallback func = NULL;
1015         pkix_ClassTable_Entry entry;
1016         PKIX_UInt32 objType;
1017 
1018         PKIX_ENTER(OBJECT, "PKIX_PL_Object_Duplicate");
1019         PKIX_NULLCHECK_TWO(firstObject, pNewObject);
1020 
1021         PKIX_CHECK(pkix_pl_Object_GetHeader
1022                     (firstObject, &firstObjectHeader, plContext),
1023                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
1024 
1025         objType = firstObjectHeader->type;
1026 
1027         if (objType >= PKIX_NUMTYPES) {
1028 #ifdef PKIX_USER_OBJECT_TYPE
1029                 pkix_ClassTable_Entry *ctEntry = NULL;
1030 
1031                 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
1032                 PR_Lock(classTableLock);
1033                 pkixErrorResult = pkix_pl_PrimHashTable_Lookup
1034                         (classTable,
1035                         (void *)&objType,
1036                         objType,
1037                         NULL,
1038                         (void **)&ctEntry,
1039                         plContext);
1040                 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
1041                 PR_Unlock(classTableLock);
1042 
1043                 if (pkixErrorResult){
1044                         PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY);
1045                 }
1046 
1047                 if ((ctEntry == NULL) || (ctEntry->duplicateFunction == NULL)) {
1048                         PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK);
1049                 } else {
1050                         func = ctEntry->duplicateFunction;
1051                 }
1052 #else
1053                 PORT_Assert (0);
1054                 pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
1055                 pkixErrorClass = PKIX_FATAL_ERROR;
1056                 goto cleanup;
1057 #endif /* PKIX_USER_OBJECT_TYPE */
1058         } else {
1059                 entry = systemClasses[objType];
1060                 func = entry.duplicateFunction;
1061                 if (!func){
1062                         PKIX_ERROR_FATAL(PKIX_UNDEFINEDDUPLICATEFUNCTION);
1063                 }
1064         }
1065 
1066         PKIX_CHECK(func(firstObject, pNewObject, plContext),
1067                     PKIX_OBJECTSPECIFICFUNCTIONFAILED);
1068 
1069 cleanup:
1070 
1071         PKIX_RETURN(OBJECT);
1072 }
1073 
1074 /*
1075  * FUNCTION: PKIX_PL_Object_Hashcode (see comments in pkix_pl_system.h)
1076  */
1077 PKIX_Error *
PKIX_PL_Object_Hashcode(PKIX_PL_Object * object,PKIX_UInt32 * pValue,void * plContext)1078 PKIX_PL_Object_Hashcode(
1079         PKIX_PL_Object *object,
1080         PKIX_UInt32 *pValue,
1081         void *plContext)
1082 {
1083         PKIX_PL_Object *objectHeader = NULL;
1084         PKIX_PL_HashcodeCallback func = NULL;
1085         pkix_ClassTable_Entry entry;
1086         PKIX_UInt32 objectHash;
1087 
1088         PKIX_ENTER(OBJECT, "PKIX_PL_Object_Hashcode");
1089         PKIX_NULLCHECK_TWO(object, pValue);
1090 
1091         /* Shift pointer from user data to object header */
1092         PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
1093                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
1094 
1095         /* if we don't have a cached copy from before, we create one */
1096         if (!objectHeader->hashcodeCached){
1097 
1098                 PKIX_UInt32 objType = objectHeader->type;
1099 
1100                 /* first, special handling for system types */
1101                 if (objType >= PKIX_NUMTYPES){
1102 #ifdef PKIX_USER_OBJECT_TYPE
1103                         pkix_ClassTable_Entry *ctEntry = NULL;
1104 
1105                         PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
1106                         PR_Lock(classTableLock);
1107                         pkixErrorResult = pkix_pl_PrimHashTable_Lookup
1108                                 (classTable,
1109                                 (void *)&objType,
1110                                 objType,
1111                                 NULL,
1112                                 (void **)&ctEntry,
1113                                 plContext);
1114                         PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
1115                         PR_Unlock(classTableLock);
1116 
1117                         if (pkixErrorResult){
1118                                 PKIX_ERROR_FATAL
1119                                         (PKIX_ERRORGETTINGCLASSTABLEENTRY);
1120                         }
1121 
1122                         if ((ctEntry == NULL) ||
1123                             (ctEntry->hashcodeFunction == NULL)) {
1124                                 PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK);
1125                         }
1126 
1127                         func = ctEntry->hashcodeFunction;
1128 #else
1129                         PORT_Assert (0);
1130                         pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
1131                         pkixErrorClass = PKIX_FATAL_ERROR;
1132                         goto cleanup;
1133 #endif /* PKIX_USER_OBJECT_TYPE */
1134                 } else {
1135                         entry = systemClasses[objType];
1136                         func = entry.hashcodeFunction;
1137                         if (func == NULL){
1138                                 func = pkix_pl_Object_Hashcode_Default;
1139                         }
1140                 }
1141 
1142                 PKIX_CHECK(func(object, &objectHash, plContext),
1143                             PKIX_OBJECTSPECIFICFUNCTIONFAILED);
1144 
1145                 if (!objectHeader->hashcodeCached){
1146 
1147                         PKIX_CHECK(pkix_LockObject(object, plContext),
1148                                     PKIX_ERRORLOCKINGOBJECT);
1149 
1150                         if (!objectHeader->hashcodeCached){
1151                                 /* save cached copy in case we need it again */
1152                                 objectHeader->hashcode = objectHash;
1153                                 objectHeader->hashcodeCached = PKIX_TRUE;
1154                         }
1155 
1156                         PKIX_CHECK(pkix_UnlockObject(object, plContext),
1157                                     PKIX_ERRORUNLOCKINGOBJECT);
1158                 }
1159         }
1160 
1161         *pValue = objectHeader->hashcode;
1162 
1163 cleanup:
1164 
1165         PKIX_RETURN(OBJECT);
1166 }
1167 
1168 /*
1169  * FUNCTION: PKIX_PL_Object_ToString (see comments in pkix_pl_system.h)
1170  */
1171 PKIX_Error *
PKIX_PL_Object_ToString(PKIX_PL_Object * object,PKIX_PL_String ** pString,void * plContext)1172 PKIX_PL_Object_ToString(
1173         PKIX_PL_Object *object,
1174         PKIX_PL_String **pString,
1175         void *plContext)
1176 {
1177         PKIX_PL_Object *objectHeader = NULL;
1178         PKIX_PL_ToStringCallback func = NULL;
1179         pkix_ClassTable_Entry entry;
1180         PKIX_PL_String *objectString = NULL;
1181 
1182         PKIX_ENTER(OBJECT, "PKIX_PL_Object_ToString");
1183         PKIX_NULLCHECK_TWO(object, pString);
1184 
1185         /* Shift pointer from user data to object header */
1186         PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
1187                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
1188 
1189         /* if we don't have a cached copy from before, we create one */
1190         if (!objectHeader->stringRep){
1191 
1192                 PKIX_UInt32 objType = objectHeader->type;
1193 
1194                 if (objType >= PKIX_NUMTYPES){
1195 #ifdef PKIX_USER_OBJECT_TYPE
1196                         pkix_ClassTable_Entry *ctEntry = NULL;
1197 
1198                         PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
1199                         PR_Lock(classTableLock);
1200                         pkixErrorResult = pkix_pl_PrimHashTable_Lookup
1201                                 (classTable,
1202                                 (void *)&objType,
1203                                 objType,
1204                                 NULL,
1205                                 (void **)&ctEntry,
1206                                 plContext);
1207                         PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
1208                         PR_Unlock(classTableLock);
1209                         if (pkixErrorResult){
1210                                 PKIX_ERROR_FATAL
1211                                         (PKIX_ERRORGETTINGCLASSTABLEENTRY);
1212                         }
1213 
1214                         if ((ctEntry == NULL) ||
1215                             (ctEntry->toStringFunction == NULL)) {
1216                                 PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK);
1217                         }
1218 
1219                         func = ctEntry->toStringFunction;
1220 #else
1221                         PORT_Assert (0);
1222                         pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
1223                         pkixErrorClass = PKIX_FATAL_ERROR;
1224                         goto cleanup;
1225 #endif /* PKIX_USER_OBJECT_TYPE */
1226                 } else {
1227                         entry = systemClasses[objType];
1228                         func = entry.toStringFunction;
1229                         if (func == NULL){
1230                                 func = pkix_pl_Object_ToString_Default;
1231                         }
1232                 }
1233 
1234                 PKIX_CHECK(func(object, &objectString, plContext),
1235                             PKIX_OBJECTSPECIFICFUNCTIONFAILED);
1236 
1237                 if (!objectHeader->stringRep){
1238 
1239                         PKIX_CHECK(pkix_LockObject(object, plContext),
1240                                     PKIX_ERRORLOCKINGOBJECT);
1241 
1242                         if (!objectHeader->stringRep){
1243                                 /* save a cached copy */
1244                                 objectHeader->stringRep = objectString;
1245                                 objectString = NULL;
1246                         }
1247 
1248                         PKIX_CHECK(pkix_UnlockObject(object, plContext),
1249                                     PKIX_ERRORUNLOCKINGOBJECT);
1250                 }
1251         }
1252 
1253 
1254         *pString = objectHeader->stringRep;
1255         objectHeader->stringRep = NULL;
1256 
1257 cleanup:
1258         if (objectHeader) {
1259             PKIX_DECREF(objectHeader->stringRep);
1260         }
1261         PKIX_DECREF(objectString);
1262 
1263         PKIX_RETURN(OBJECT);
1264 }
1265 
1266 /*
1267  * FUNCTION: PKIX_PL_Object_InvalidateCache (see comments in pkix_pl_system.h)
1268  */
1269 PKIX_Error *
PKIX_PL_Object_InvalidateCache(PKIX_PL_Object * object,void * plContext)1270 PKIX_PL_Object_InvalidateCache(
1271         PKIX_PL_Object *object,
1272         void *plContext)
1273 {
1274         PKIX_PL_Object *objectHeader = NULL;
1275 
1276         PKIX_ENTER(OBJECT, "PKIX_PL_Object_InvalidateCache");
1277         PKIX_NULLCHECK_ONE(object);
1278 
1279         /* Shift pointer from user data to object header */
1280         PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
1281                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
1282 
1283         PKIX_CHECK(pkix_LockObject(object, plContext),
1284                     PKIX_ERRORLOCKINGOBJECT);
1285 
1286         /* invalidate hashcode */
1287         objectHeader->hashcode = 0;
1288         objectHeader->hashcodeCached = PKIX_FALSE;
1289 
1290         PKIX_DECREF(objectHeader->stringRep);
1291 
1292         PKIX_CHECK(pkix_UnlockObject(object, plContext),
1293                     PKIX_ERRORUNLOCKINGOBJECT);
1294 
1295 cleanup:
1296 
1297         PKIX_RETURN(OBJECT);
1298 }
1299 
1300 /*
1301  * FUNCTION: PKIX_PL_Object_Compare (see comments in pkix_pl_system.h)
1302  */
1303 PKIX_Error *
PKIX_PL_Object_Compare(PKIX_PL_Object * firstObject,PKIX_PL_Object * secondObject,PKIX_Int32 * pResult,void * plContext)1304 PKIX_PL_Object_Compare(
1305         PKIX_PL_Object *firstObject,
1306         PKIX_PL_Object *secondObject,
1307         PKIX_Int32 *pResult,
1308         void *plContext)
1309 {
1310         PKIX_PL_Object *firstObjectHeader = NULL;
1311         PKIX_PL_Object *secondObjectHeader = NULL;
1312         PKIX_PL_ComparatorCallback func = NULL;
1313         pkix_ClassTable_Entry entry;
1314         PKIX_UInt32 objType;
1315 
1316         PKIX_ENTER(OBJECT, "PKIX_PL_Object_Compare");
1317         PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
1318 
1319         /* Shift pointer from user data to object header */
1320         PKIX_CHECK(pkix_pl_Object_GetHeader
1321                     (firstObject, &firstObjectHeader, plContext),
1322                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
1323 
1324         /* Shift pointer from user data to object header */
1325         PKIX_CHECK(pkix_pl_Object_GetHeader
1326                     (secondObject, &secondObjectHeader, plContext),
1327                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
1328 
1329         objType = firstObjectHeader->type;
1330 
1331         if (objType >= PKIX_NUMTYPES){
1332 #ifdef PKIX_USER_OBJECT_TYPE
1333                 pkix_ClassTable_Entry *ctEntry = NULL;
1334 
1335                 PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
1336                 PR_Lock(classTableLock);
1337                 pkixErrorResult = pkix_pl_PrimHashTable_Lookup
1338                         (classTable,
1339                         (void *)&objType,
1340                         objType,
1341                         NULL,
1342                         (void **)&ctEntry,
1343                         plContext);
1344                 PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
1345                 PR_Unlock(classTableLock);
1346                 if (pkixErrorResult){
1347                         PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY);
1348                 }
1349 
1350                 if ((ctEntry == NULL) || (ctEntry->comparator == NULL)) {
1351                         PKIX_ERROR_FATAL(PKIX_UNDEFINEDCOMPARATOR);
1352                 }
1353 
1354                 func = ctEntry->comparator;
1355 #else
1356                 PORT_Assert (0);
1357                 pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
1358                 pkixErrorClass = PKIX_FATAL_ERROR;
1359                 goto cleanup;
1360 #endif /* PKIX_USER_OBJECT_TYPE */
1361         } else {
1362                 /* special handling for system types */
1363                 entry = systemClasses[objType];
1364                 func = entry.comparator;
1365                 if (!func){
1366                         PKIX_ERROR(PKIX_UNDEFINEDCOMPARATOR);
1367                 }
1368         }
1369 
1370         PKIX_CHECK(func(firstObject, secondObject, pResult, plContext),
1371                     PKIX_OBJECTSPECIFICFUNCTIONFAILED);
1372 
1373 cleanup:
1374 
1375         PKIX_RETURN(OBJECT);
1376 }
1377 
1378 /*
1379  * FUNCTION: PKIX_PL_Object_Lock (see comments in pkix_pl_system.h)
1380  */
1381 PKIX_Error *
PKIX_PL_Object_Lock(PKIX_PL_Object * object,void * plContext)1382 PKIX_PL_Object_Lock(
1383         PKIX_PL_Object *object,
1384         void *plContext)
1385 {
1386         PKIX_ENTER(OBJECT, "PKIX_PL_Object_Lock");
1387         PKIX_NULLCHECK_ONE(object);
1388 
1389         PKIX_CHECK(pkix_LockObject(object, plContext),
1390                     PKIX_LOCKOBJECTFAILED);
1391 
1392 cleanup:
1393 
1394         PKIX_RETURN(OBJECT);
1395 }
1396 
1397 /*
1398  * FUNCTION: PKIX_PL_Object_Unlock (see comments in pkix_pl_system.h)
1399  */
1400 PKIX_Error *
PKIX_PL_Object_Unlock(PKIX_PL_Object * object,void * plContext)1401 PKIX_PL_Object_Unlock(
1402         PKIX_PL_Object *object,
1403         void *plContext)
1404 {
1405         PKIX_ENTER(OBJECT, "PKIX_PL_Object_Unlock");
1406         PKIX_NULLCHECK_ONE(object);
1407 
1408         PKIX_CHECK(pkix_UnlockObject(object, plContext),
1409                     PKIX_UNLOCKOBJECTFAILED);
1410 
1411 cleanup:
1412 
1413         PKIX_RETURN(OBJECT);
1414 }
1415 
1416 
1417 /*
1418  * FUNCTION: PKIX_PL_Object_GetType (see comments in pkix_pl_system.h)
1419  */
1420 PKIX_Error *
PKIX_PL_Object_GetType(PKIX_PL_Object * object,PKIX_UInt32 * pType,void * plContext)1421 PKIX_PL_Object_GetType(
1422         PKIX_PL_Object *object,
1423         PKIX_UInt32 *pType,
1424         void *plContext)
1425 {
1426         PKIX_PL_Object *objectHeader = NULL;
1427 
1428         PKIX_ENTER(OBJECT, "PKIX_PL_Object_GetType");
1429         PKIX_NULLCHECK_TWO(object, pType);
1430 
1431         /* Shift pointer from user data to object header */
1432         PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
1433                     PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
1434 
1435         *pType = objectHeader->type;
1436 
1437 cleanup:
1438 
1439         PKIX_RETURN(OBJECT);
1440 }
1441