security/nss/lib/base/tracker.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     5 /*
     6  * tracker.c
     7  * 
     8  * This file contains the code used by the pointer-tracking calls used
     9  * in the debug builds to catch bad pointers.  The entire contents are
    10  * only available in debug builds (both internal and external builds).
    11  */
    13 #ifndef BASE_H
    14 #include "base.h"
    15 #endif /* BASE_H */
    17 #ifdef DEBUG
    18 /*
    19  * identity_hash
    20  *
    21  * This static callback is a PLHashFunction as defined in plhash.h
    22  * It merely returns the value of the object pointer as its hash.
    23  * There are no possible errors.
    24  */
    26 static PLHashNumber PR_CALLBACK
    27 identity_hash
    28 (
    29   const void *key
    30 )
    31 {
    32   return (PLHashNumber)key;
    33 }
    35 /*
    36  * trackerOnceFunc
    37  *
    38  * This function is called once, using the nssCallOnce function above.
    39  * It creates a new pointer tracker object; initialising its hash
    40  * table and protective lock.
    41  */
    43 static PRStatus
    44 trackerOnceFunc
    45 (
    46   void *arg
    47 )
    48 {
    49   nssPointerTracker *tracker = (nssPointerTracker *)arg;
    51   tracker->lock = PZ_NewLock(nssILockOther);
    52   if( (PZLock *)NULL == tracker->lock ) {
    53     return PR_FAILURE;
    54   }
    56   tracker->table = PL_NewHashTable(0, 
    57                                    identity_hash, 
    58                                    PL_CompareValues,
    59                                    PL_CompareValues,
    60                                    (PLHashAllocOps *)NULL, 
    61                                    (void *)NULL);
    62   if( (PLHashTable *)NULL == tracker->table ) {
    63     PZ_DestroyLock(tracker->lock);
    64     tracker->lock = (PZLock *)NULL;
    65     return PR_FAILURE;
    66   }
    68   return PR_SUCCESS;
    69 }
    71 /*
    72  * nssPointerTracker_initialize
    73  *
    74  * This method is only present in debug builds.
    75  * 
    76  * This routine initializes an nssPointerTracker object.  Note that
    77  * the object must have been declared *static* to guarantee that it
    78  * is in a zeroed state initially.  This routine is idempotent, and
    79  * may even be safely called by multiple threads simultaneously with 
    80  * the same argument.  This routine returns a PRStatus value; if 
    81  * successful, it will return PR_SUCCESS.  On failure it will set an 
    82  * error on the error stack and return PR_FAILURE.
    83  *
    84  * The error may be one of the following values:
    85  *  NSS_ERROR_NO_MEMORY
    86  *
    87  * Return value:
    88  *  PR_SUCCESS
    89  *  PR_FAILURE
    90  */
    92 NSS_IMPLEMENT PRStatus
    93 nssPointerTracker_initialize
    94 (
    95   nssPointerTracker *tracker
    96 )
    97 {
    98   PRStatus rv = PR_CallOnceWithArg(&tracker->once, trackerOnceFunc, tracker);
    99   if( PR_SUCCESS != rv ) {
   100     nss_SetError(NSS_ERROR_NO_MEMORY);
   101   }
   103   return rv;
   104 }
   106 #ifdef DONT_DESTROY_EMPTY_TABLES
   107 /* See same #ifdef below */
   108 /*
   109  * count_entries
   110  *
   111  * This static routine is a PLHashEnumerator, as defined in plhash.h.
   112  * It merely causes the enumeration function to count the number of
   113  * entries.
   114  */
   116 static PRIntn PR_CALLBACK
   117 count_entries
   118 (
   119   PLHashEntry *he,
   120   PRIntn index,
   121   void *arg
   122 )
   123 {
   124   return HT_ENUMERATE_NEXT;
   125 }
   126 #endif /* DONT_DESTROY_EMPTY_TABLES */
   128 /*
   129  * zero_once
   130  *
   131  * This is a guaranteed zeroed once block.  It's used to help clear
   132  * the tracker.
   133  */
   135 static const PRCallOnceType zero_once;
   137 /*
   138  * nssPointerTracker_finalize
   139  *
   140  * This method is only present in debug builds.
   141  * 
   142  * This routine returns the nssPointerTracker object to the pre-
   143  * initialized state, releasing all resources used by the object.
   144  * It will *NOT* destroy the objects being tracked by the pointer
   145  * (should any remain), and therefore cannot be used to "sweep up"
   146  * remaining objects.  This routine returns a PRStatus value; if
   147  * successful, it will return PR_SUCCES.  On failure it will set an
   148  * error on the error stack and return PR_FAILURE.  If any objects
   149  * remain in the tracker when it is finalized, that will be treated
   150  * as an error.
   151  *
   152  * The error may be one of the following values:
   153  *  NSS_ERROR_INVALID_POINTER
   154  *  NSS_ERROR_TRACKER_NOT_INITIALIZED
   155  *  NSS_ERROR_TRACKER_NOT_EMPTY
   156  *
   157  * Return value:
   158  *  PR_SUCCESS
   159  *  PR_FAILURE
   160  */
   162 NSS_IMPLEMENT PRStatus
   163 nssPointerTracker_finalize
   164 (
   165   nssPointerTracker *tracker
   166 )
   167 {
   168   PZLock *lock;
   170   if( (nssPointerTracker *)NULL == tracker ) {
   171     nss_SetError(NSS_ERROR_INVALID_POINTER);
   172     return PR_FAILURE;
   173   }
   175   if( (PZLock *)NULL == tracker->lock ) {
   176     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
   177     return PR_FAILURE;
   178   }
   180   lock = tracker->lock;
   181   PZ_Lock(lock);
   183   if( (PLHashTable *)NULL == tracker->table ) {
   184     PZ_Unlock(lock);
   185     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
   186     return PR_FAILURE;
   187   }
   189 #ifdef DONT_DESTROY_EMPTY_TABLES
   190   /*
   191    * I changed my mind; I think we don't want this after all.
   192    * Comments?
   193    */
   194   count = PL_HashTableEnumerateEntries(tracker->table, 
   195                                        count_entries,
   196                                        (void *)NULL);
   198   if( 0 != count ) {
   199     PZ_Unlock(lock);
   200     nss_SetError(NSS_ERROR_TRACKER_NOT_EMPTY);
   201     return PR_FAILURE;
   202   }
   203 #endif /* DONT_DESTROY_EMPTY_TABLES */
   205   PL_HashTableDestroy(tracker->table);
   206   /* memset(tracker, 0, sizeof(nssPointerTracker)); */
   207   tracker->once = zero_once;
   208   tracker->lock = (PZLock *)NULL;
   209   tracker->table = (PLHashTable *)NULL;
   211   PZ_Unlock(lock);
   212   PZ_DestroyLock(lock);
   214   return PR_SUCCESS;
   215 }
   217 /*
   218  * nssPointerTracker_add
   219  *
   220  * This method is only present in debug builds.
   221  *
   222  * This routine adds the specified pointer to the nssPointerTracker
   223  * object.  It should be called in constructor objects to register
   224  * new valid objects.  The nssPointerTracker is threadsafe, but this
   225  * call is not idempotent.  This routine returns a PRStatus value;
   226  * if successful it will return PR_SUCCESS.  On failure it will set
   227  * an error on the error stack and return PR_FAILURE.
   228  *
   229  * The error may be one of the following values:
   230  *  NSS_ERROR_INVALID_POINTER
   231  *  NSS_ERROR_NO_MEMORY
   232  *  NSS_ERROR_TRACKER_NOT_INITIALIZED
   233  *  NSS_ERROR_DUPLICATE_POINTER
   234  *
   235  * Return value:
   236  *  PR_SUCCESS
   237  *  PR_FAILURE
   238  */
   240 NSS_IMPLEMENT PRStatus
   241 nssPointerTracker_add
   242 (
   243   nssPointerTracker *tracker,
   244   const void *pointer
   245 )
   246 {
   247   void *check;
   248   PLHashEntry *entry;
   250   if( (nssPointerTracker *)NULL == tracker ) {
   251     nss_SetError(NSS_ERROR_INVALID_POINTER);
   252     return PR_FAILURE;
   253   }
   255   if( (PZLock *)NULL == tracker->lock ) {
   256     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
   257     return PR_FAILURE;
   258   }
   260   PZ_Lock(tracker->lock);
   262   if( (PLHashTable *)NULL == tracker->table ) {
   263     PZ_Unlock(tracker->lock);
   264     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
   265     return PR_FAILURE;
   266   }
   268   check = PL_HashTableLookup(tracker->table, pointer);
   269   if( (void *)NULL != check ) {
   270     PZ_Unlock(tracker->lock);
   271     nss_SetError(NSS_ERROR_DUPLICATE_POINTER);
   272     return PR_FAILURE;
   273   }
   275   entry = PL_HashTableAdd(tracker->table, pointer, (void *)pointer);
   277   PZ_Unlock(tracker->lock);
   279   if( (PLHashEntry *)NULL == entry ) {
   280     nss_SetError(NSS_ERROR_NO_MEMORY);
   281     return PR_FAILURE;
   282   }
   284   return PR_SUCCESS;
   285 }
   287 /*
   288  * nssPointerTracker_remove
   289  *
   290  * This method is only present in debug builds.
   291  *
   292  * This routine removes the specified pointer from the 
   293  * nssPointerTracker object.  It does not call any destructor for the
   294  * object; rather, this should be called from the object's destructor.
   295  * The nssPointerTracker is threadsafe, but this call is not 
   296  * idempotent.  This routine returns a PRStatus value; if successful 
   297  * it will return PR_SUCCESS.  On failure it will set an error on the 
   298  * error stack and return PR_FAILURE.
   299  *
   300  * The error may be one of the following values:
   301  *  NSS_ERROR_INVALID_POINTER
   302  *  NSS_ERROR_TRACKER_NOT_INITIALIZED
   303  *  NSS_ERROR_POINTER_NOT_REGISTERED
   304  *
   305  * Return value:
   306  *  PR_SUCCESS
   307  *  PR_FAILURE
   308  */
   310 NSS_IMPLEMENT PRStatus
   311 nssPointerTracker_remove
   312 (
   313   nssPointerTracker *tracker,
   314   const void *pointer
   315 )
   316 {
   317   PRBool registered;
   319   if( (nssPointerTracker *)NULL == tracker ) {
   320     nss_SetError(NSS_ERROR_INVALID_POINTER);
   321     return PR_FAILURE;
   322   }
   324   if( (PZLock *)NULL == tracker->lock ) {
   325     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
   326     return PR_FAILURE;
   327   }
   329   PZ_Lock(tracker->lock);
   331   if( (PLHashTable *)NULL == tracker->table ) {
   332     PZ_Unlock(tracker->lock);
   333     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
   334     return PR_FAILURE;
   335   }
   337   registered = PL_HashTableRemove(tracker->table, pointer);
   338   PZ_Unlock(tracker->lock);
   340   if( !registered ) {
   341     nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);
   342     return PR_FAILURE;
   343   }
   345   return PR_SUCCESS;
   346 }
   348 /*
   349  * nssPointerTracker_verify
   350  *
   351  * This method is only present in debug builds.
   352  *
   353  * This routine verifies that the specified pointer has been registered
   354  * with the nssPointerTracker object.  The nssPointerTracker object is
   355  * threadsafe, and this call may be safely called from multiple threads
   356  * simultaneously with the same arguments.  This routine returns a
   357  * PRStatus value; if the pointer is registered this will return 
   358  * PR_SUCCESS.  Otherwise it will set an error on the error stack and 
   359  * return PR_FAILURE.  Although the error is suitable for leaving on 
   360  * the stack, callers may wish to augment the information available by 
   361  * placing a more type-specific error on the stack.
   362  *
   363  * The error may be one of the following values:
   364  *  NSS_ERROR_INVALID_POINTER
   365  *  NSS_ERROR_TRACKER_NOT_INITIALIZED
   366  *  NSS_ERROR_POINTER_NOT_REGISTERED
   367  *
   368  * Return value:
   369  *  PR_SUCCESS
   370  *  PR_FAILRUE
   371  */
   373 NSS_IMPLEMENT PRStatus
   374 nssPointerTracker_verify
   375 (
   376   nssPointerTracker *tracker,
   377   const void *pointer
   378 )
   379 {
   380   void *check;
   382   if( (nssPointerTracker *)NULL == tracker ) {
   383     nss_SetError(NSS_ERROR_INVALID_POINTER);
   384     return PR_FAILURE;
   385   }
   387   if( (PZLock *)NULL == tracker->lock ) {
   388     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
   389     return PR_FAILURE;
   390   }
   392   PZ_Lock(tracker->lock);
   394   if( (PLHashTable *)NULL == tracker->table ) {
   395     PZ_Unlock(tracker->lock);
   396     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
   397     return PR_FAILURE;
   398   }
   400   check = PL_HashTableLookup(tracker->table, pointer);
   401   PZ_Unlock(tracker->lock);
   403   if( (void *)NULL == check ) {
   404     nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);
   405     return PR_FAILURE;
   406   }
   408   return PR_SUCCESS;
   409 }
   411 #endif /* DEBUG */

mercurial