From: keith@taligent.com (Keith Rollin)
Subject: Re: dereferencing Handles( was Re: incrementation differences/THINK C 4.0 vs. 5.0)
Organization: Taligent
Date: Tue, 25 Aug 1992 19:22:51 GMT

In article <1992Aug25.150911.19008@bnr.ca>, gcote@crchh74f.BNR.CA (Gary Cote)
writes:
> 
> In article <1992Aug24.221630.4730@Csli.Stanford.EDU>,
> mmarx@csli.stanford.edu (Matthew Marx) writes:
> 	< stuff about how he's maintaining someone else's code deleted >
> |>Boolean
> |>nxtWrd(char **theDataPtr, char *lab, int  tabs)
> |>{
> |>	char *temp;
> |>	int i=0;
> |>	
> |>	temp = *theDataPtr;
> |>	
> |>	while(*temp == '\t') 
> |>	{
> |>		temp++; i++;
> |>	}
> 	< more stuff regarding ThinkC's order of operator evaluation >
> 
> 	Does this snippet violate the rule of safe handle conventions? It seems
> to me that 
> once theDataPtr is dereferenced and copied into temp, this leaves him
> open to the great 
> disappearing memory trick. Assuming that the block theDataPtr is
> relocatable and 
> not locked, temp has the potential for becoming obsolete if the block is
moved.
> 
> 	If I am incorrect, I apologize. I haven't been programming the Mac very long.
> 
> 	Would someone please post a clarification ( my access to e-mail is
> restricted ).


Fortunately for the entire world, the Mac Memory Manager moves blocks only at
very well defined times. One very gross rule that you could follow is that if
you don't call any Memory Manager traps (either explicitly or implicitly by
calling subroutines or other traps that in turn call the Memory Manager), then
memory blocks won't move. Using our WayBack machine and resurrecting the
original code:

Boolean nxtWrd(char **theDataPtr, char *lab, int  tabs)
{
	char *temp;
	int i=0;
	
	temp = *theDataPtr;
	
	while(*temp == '\t') 
		temp++; i++;

	if (i == tabs) {
		i = 0;
		while (temp[i] && (i<(WORDMAX-1)) && (temp[i] != '\n')) {
			lab[i] = temp[i++];  //****THIS IS THE PROBLEM
		}
		lab[i] = '\0';
		while (temp[i] && temp[i]!= '\n') i++;
		if (temp[i] == '\n') i++;
		*theDataPtr = temp+i;
		return TRUE;
	}
	else return FALSE;
}


You'll see a complete lack of calls to the Toolbox or OS. Therefore, memory will
not move, and his pointers will be safe.

OK, OK, before some hotshot jumps down my throat, there _is_ a case you have to
look out for with the above code. I mentioned earlier that even implicit calls
to the Memory Manager could get you into trouble. Sometimes these implicit calls
are very subtle. For instance, assume that the above code is compiled on a
system where ints are 32-bits long (like they are under MPW). Also assume that,
instead of pointing to chars, "temp" points to something larger. In order to
create the offset to the appropriate entry when working with 32-bit indexes, the
compiler will call a standard library routine to perform the long
multiplication. IF THE CODE SEGMENT HOLDING THE LIBRARY MULTIPLICATION ROUTINE
IS NOT LOADED, it will automatically be loaded, which will cause memory blocks
to move around, possibly invalidating "temp". Normally, this won't happen,
because people usually put those library routines in their Main segment, which
is always loaded. But it's something to keep in mind.

--
Keith Rollin
Phantom Programmer
Taligent, Inc.