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