From: keith@taligent.com (Keith Rollin)
Newsgroups: comp.sys.mac.programmer
Subject: Re: Verifying valid handles, how to?
Date: 23 Jan 93 00:04:58 GMT
Followup-To: comp.sys.mac.programmer
Organization: Taligent

In article <NEERI.93Jan22190934@iis.ethz.ch>, neeri@iis.ethz.ch (Matthias
Neeracher) wrote:
> 
> In article <1993Jan22.015520.1@fnalo.fnal.gov>, gwatts@fnalo.fnal.gov writes:
> >   At any rate, I was thinking.  I've got only indirect objects in my project.
> > This means every object is a handle, right?  Well, why not, in the debug
> > version of the message dispatcher (oopDebug library) put a little code that
> > will check the object is infact allocated as a handle?
> >   I checked out the routine in msg.c (in the oops Libraries folder), and
> > the handle is stored in register a1.  I don't know, however, how to check
> > if it is a valid handle without causing an error (bus or otherwise) of
> > somesort.  Especially if it is a random number!  Anyone know?  Is there
> > some memory manager routine, given a suspected handle, will tell me this?
> 
> Here you go. This code is not guaranteed to work 100% of the time, but I doubt
> you will get it to produce an address error for any normal memory setup (One
> exception I can think of are macs with a memory upgrade that makes the ROM
> appear in the middle of the application heap).
> 
> /* Heuristic to determine whether a given address is a Handle            */
> /* Based on the articles of Lloyd Lim and Matthew T Russotto in the UMPG */
> /* This code may be redistributed without any restrictions               */
> 
> Boolean RealHandle(void * addr)
> {
>    THz   sysZone;
>    THz   applZone;
>    THz   heapZone;
>    
>    addr  =  StripAddress(addr);
>    if (addr && !((long) addr & 1))  {
>       sysZone  =  SystemZone();
>       applZone =  ApplicZone();
>       if (addr >= (Ptr) &sysZone->heapData   && 
>           addr <  (Ptr) sysZone->bkLim          ||
>           addr >= (Ptr) &applZone->heapData  && 
>           addr <  (Ptr) applZone->bkLim
>          )
>          if (*(long *)addr && !(*(long *)addr & 1)) {
>             heapZone =  HandleZone(addr);
>             if (!MemError())
>                if (heapZone == sysZone || heapZone == applZone)
>                   return true;
>          }
>    }
>    
>    return false;
> }

I think that the above routine tries to validate any value that you might
have lying around. However, if you have a value that you know at one time
was a handle, you might want to check to see if it's on the free chain or
not (this code is from MacApp):

Boolean IsFreeHandle(Handle aHandle)
{
	THz applZone = ApplicZone();
	Handle currHandle = (Handle) applZone->hFstFree;

	while (currHandle != NULL)
	{
		if (currHandle == aHandle)
			return TRUE;
		currHandle = (Handle) * currHandle;
	}
	return FALSE;
}

If course, nothing will help you if the master pointer has been
re-allocated. Your old handle will now be pointing to a new, perfectly
valid block of memory. I think the only thing you can do at that point is
check the handle size against sizeof(TYourClass).

Greg Marriott (who was seen the other night at the Red Pepper with Cindy
Jasper) wrote an INIT that tries to detect double-dispose bugs. It's on
Apple's Developer CD and probably other places. Here are the release notes
for your reading pleasure:

;
;	DoubleTrouble - by Greg Marriott
;
;	) 1992, Apple Computer, Inc.
;
;	DoubleTrouble is a debugging utility made to catch a common programming
error:
;	freeing a handle that has already been freed.  (I call these errors
Rdouble
;	dispose bugsSI)
;
;	When _DisposeHandle is called on a handle, the memory manager adds the
handle
;	to its Rfree list,S a linked list of handles available for the allocator
to use.
;	Calling _DisposeHandle on that handle again is usually benign.  The
memory
;	manager dereferences the handle, pointing to the next handle in the free
list.
;	If the the dereferenced handle points to the first handle in a master
pointer block,
;	however, the handle appears valid because it points to a real block.  The
memory
;	manager fails to realize the block is NOT a relocatable block (all master
pointer
;	blocks are nonrelocatable), and marks it free (yikes!).  The freed master
pointer
;	block is then used in a future allocation (usually very soon after being
freed).
;	This mangles several master pointers and the free list.  Crashes soon
follow.
;
;	This kind of bug is very hard to track down, and usually difficult to
reproduce,
;	because master pointer blocks contain 64 handles (by default, some
programs
;	change this behavior).  So, this situation only comes up about 1/64th of
the
;	time.  When it happens, though, the results are inevitably catastrophic.
;
;	DoubleTrouble compares each handle being disposed to every handle in the
free list of
;	the zone containing the handle.  If the handle is already in the free
list, DoubleTrouble
;	breaks into the debugger with a message indicating whatUs going on. 
Continuing execution
;	will stuff memWZErr (WhichZone failed, -111) into MemErr and d0 and
return to the caller
;	(and NOT call through to _DisposeHandle).
;	

-----
Keith Rollin
Phantom Programmer
Taligent, Inc.
Newsgroups: comp.sys.mac.programmer