1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 static const char CVS_ID
[] = "@(#) $RCSfile: tracker.c,v $ $Revision: 1.7 $ $Date: 2008/02/23 05:29:24 $";
44 * This file contains the code used by the pointer-tracking calls used
45 * in the debug builds to catch bad pointers. The entire contents are
46 * only available in debug builds (both internal and external builds).
57 * This static callback is a PLHashFunction as defined in plhash.h
58 * It merely returns the value of the object pointer as its hash.
59 * There are no possible errors.
62 static PLHashNumber PR_CALLBACK
68 return (PLHashNumber
)key
;
74 * This function is called once, using the nssCallOnce function above.
75 * It creates a new pointer tracker object; initialising its hash
76 * table and protective lock.
85 nssPointerTracker
*tracker
= (nssPointerTracker
*)arg
;
87 tracker
->lock
= PZ_NewLock(nssILockOther
);
88 if( (PZLock
*)NULL
== tracker
->lock
) {
92 tracker
->table
= PL_NewHashTable(0,
96 (PLHashAllocOps
*)NULL
,
98 if( (PLHashTable
*)NULL
== tracker
->table
) {
99 PZ_DestroyLock(tracker
->lock
);
100 tracker
->lock
= (PZLock
*)NULL
;
108 * nssPointerTracker_initialize
110 * This method is only present in debug builds.
112 * This routine initializes an nssPointerTracker object. Note that
113 * the object must have been declared *static* to guarantee that it
114 * is in a zeroed state initially. This routine is idempotent, and
115 * may even be safely called by multiple threads simultaneously with
116 * the same argument. This routine returns a PRStatus value; if
117 * successful, it will return PR_SUCCESS. On failure it will set an
118 * error on the error stack and return PR_FAILURE.
120 * The error may be one of the following values:
121 * NSS_ERROR_NO_MEMORY
128 NSS_IMPLEMENT PRStatus
129 nssPointerTracker_initialize
131 nssPointerTracker
*tracker
134 PRStatus rv
= PR_CallOnceWithArg(&tracker
->once
, trackerOnceFunc
, tracker
);
135 if( PR_SUCCESS
!= rv
) {
136 nss_SetError(NSS_ERROR_NO_MEMORY
);
142 #ifdef DONT_DESTROY_EMPTY_TABLES
143 /* See same #ifdef below */
147 * This static routine is a PLHashEnumerator, as defined in plhash.h.
148 * It merely causes the enumeration function to count the number of
152 static PRIntn PR_CALLBACK
160 return HT_ENUMERATE_NEXT
;
162 #endif /* DONT_DESTROY_EMPTY_TABLES */
167 * This is a guaranteed zeroed once block. It's used to help clear
171 static const PRCallOnceType zero_once
;
174 * nssPointerTracker_finalize
176 * This method is only present in debug builds.
178 * This routine returns the nssPointerTracker object to the pre-
179 * initialized state, releasing all resources used by the object.
180 * It will *NOT* destroy the objects being tracked by the pointer
181 * (should any remain), and therefore cannot be used to "sweep up"
182 * remaining objects. This routine returns a PRStatus value; if
183 * successful, it will return PR_SUCCES. On failure it will set an
184 * error on the error stack and return PR_FAILURE. If any objects
185 * remain in the tracker when it is finalized, that will be treated
188 * The error may be one of the following values:
189 * NSS_ERROR_INVALID_POINTER
190 * NSS_ERROR_TRACKER_NOT_INITIALIZED
191 * NSS_ERROR_TRACKER_NOT_EMPTY
198 NSS_IMPLEMENT PRStatus
199 nssPointerTracker_finalize
201 nssPointerTracker
*tracker
206 if( (nssPointerTracker
*)NULL
== tracker
) {
207 nss_SetError(NSS_ERROR_INVALID_POINTER
);
211 if( (PZLock
*)NULL
== tracker
->lock
) {
212 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED
);
216 lock
= tracker
->lock
;
219 if( (PLHashTable
*)NULL
== tracker
->table
) {
221 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED
);
225 #ifdef DONT_DESTROY_EMPTY_TABLES
227 * I changed my mind; I think we don't want this after all.
230 count
= PL_HashTableEnumerateEntries(tracker
->table
,
236 nss_SetError(NSS_ERROR_TRACKER_NOT_EMPTY
);
239 #endif /* DONT_DESTROY_EMPTY_TABLES */
241 PL_HashTableDestroy(tracker
->table
);
242 /* memset(tracker, 0, sizeof(nssPointerTracker)); */
243 tracker
->once
= zero_once
;
244 tracker
->lock
= (PZLock
*)NULL
;
245 tracker
->table
= (PLHashTable
*)NULL
;
248 PZ_DestroyLock(lock
);
254 * nssPointerTracker_add
256 * This method is only present in debug builds.
258 * This routine adds the specified pointer to the nssPointerTracker
259 * object. It should be called in constructor objects to register
260 * new valid objects. The nssPointerTracker is threadsafe, but this
261 * call is not idempotent. This routine returns a PRStatus value;
262 * if successful it will return PR_SUCCESS. On failure it will set
263 * an error on the error stack and return PR_FAILURE.
265 * The error may be one of the following values:
266 * NSS_ERROR_INVALID_POINTER
267 * NSS_ERROR_NO_MEMORY
268 * NSS_ERROR_TRACKER_NOT_INITIALIZED
269 * NSS_ERROR_DUPLICATE_POINTER
276 NSS_IMPLEMENT PRStatus
277 nssPointerTracker_add
279 nssPointerTracker
*tracker
,
286 if( (nssPointerTracker
*)NULL
== tracker
) {
287 nss_SetError(NSS_ERROR_INVALID_POINTER
);
291 if( (PZLock
*)NULL
== tracker
->lock
) {
292 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED
);
296 PZ_Lock(tracker
->lock
);
298 if( (PLHashTable
*)NULL
== tracker
->table
) {
299 PZ_Unlock(tracker
->lock
);
300 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED
);
304 check
= PL_HashTableLookup(tracker
->table
, pointer
);
305 if( (void *)NULL
!= check
) {
306 PZ_Unlock(tracker
->lock
);
307 nss_SetError(NSS_ERROR_DUPLICATE_POINTER
);
311 entry
= PL_HashTableAdd(tracker
->table
, pointer
, (void *)pointer
);
313 PZ_Unlock(tracker
->lock
);
315 if( (PLHashEntry
*)NULL
== entry
) {
316 nss_SetError(NSS_ERROR_NO_MEMORY
);
324 * nssPointerTracker_remove
326 * This method is only present in debug builds.
328 * This routine removes the specified pointer from the
329 * nssPointerTracker object. It does not call any destructor for the
330 * object; rather, this should be called from the object's destructor.
331 * The nssPointerTracker is threadsafe, but this call is not
332 * idempotent. This routine returns a PRStatus value; if successful
333 * it will return PR_SUCCESS. On failure it will set an error on the
334 * error stack and return PR_FAILURE.
336 * The error may be one of the following values:
337 * NSS_ERROR_INVALID_POINTER
338 * NSS_ERROR_TRACKER_NOT_INITIALIZED
339 * NSS_ERROR_POINTER_NOT_REGISTERED
346 NSS_IMPLEMENT PRStatus
347 nssPointerTracker_remove
349 nssPointerTracker
*tracker
,
355 if( (nssPointerTracker
*)NULL
== tracker
) {
356 nss_SetError(NSS_ERROR_INVALID_POINTER
);
360 if( (PZLock
*)NULL
== tracker
->lock
) {
361 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED
);
365 PZ_Lock(tracker
->lock
);
367 if( (PLHashTable
*)NULL
== tracker
->table
) {
368 PZ_Unlock(tracker
->lock
);
369 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED
);
373 registered
= PL_HashTableRemove(tracker
->table
, pointer
);
374 PZ_Unlock(tracker
->lock
);
377 nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED
);
385 * nssPointerTracker_verify
387 * This method is only present in debug builds.
389 * This routine verifies that the specified pointer has been registered
390 * with the nssPointerTracker object. The nssPointerTracker object is
391 * threadsafe, and this call may be safely called from multiple threads
392 * simultaneously with the same arguments. This routine returns a
393 * PRStatus value; if the pointer is registered this will return
394 * PR_SUCCESS. Otherwise it will set an error on the error stack and
395 * return PR_FAILURE. Although the error is suitable for leaving on
396 * the stack, callers may wish to augment the information available by
397 * placing a more type-specific error on the stack.
399 * The error may be one of the following values:
400 * NSS_ERROR_INVALID_POINTER
401 * NSS_ERROR_TRACKER_NOT_INITIALIZED
402 * NSS_ERROR_POINTER_NOT_REGISTERED
409 NSS_IMPLEMENT PRStatus
410 nssPointerTracker_verify
412 nssPointerTracker
*tracker
,
418 if( (nssPointerTracker
*)NULL
== tracker
) {
419 nss_SetError(NSS_ERROR_INVALID_POINTER
);
423 if( (PZLock
*)NULL
== tracker
->lock
) {
424 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED
);
428 PZ_Lock(tracker
->lock
);
430 if( (PLHashTable
*)NULL
== tracker
->table
) {
431 PZ_Unlock(tracker
->lock
);
432 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED
);
436 check
= PL_HashTableLookup(tracker
->table
, pointer
);
437 PZ_Unlock(tracker
->lock
);
439 if( (void *)NULL
== check
) {
440 nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED
);