tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pkix_pl_object.c (46788B)


      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 *
     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 *
    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 *
    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 *
    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 *
    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 *
    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 *
    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 *
    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 *
    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 *
    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 *
    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 *
    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 *
    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 *
   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 *
   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 *
   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 *
   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 *
   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 *
   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 *
   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 *
   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 }