[comp.sys.mac.programmer] Why won't ResError return the right message?

2fmlcalls@kuhub.cc.ukans.edu (05/06/91)

> Even though GetResource couldn'thave found the resource (because
> it wasn't there), ResError returned a 0, indicating that nothing
> was wrong.  Needless to say, the first time I referred to the
> resource, I got a Bus Error exception, because I was following
> the invalid handle out into La-La Land.
> 
> Why didn't ResError tell me there was a problem?
> 
> --Kurisuto
> un020070@vaxa.wvnet.edu

I've seen it documented that ResError doesn't always return 0.  I think the
preferred method is to check the resource hanfter you read it in.  Check for
nil.  

if (myRes = nil) then ....

  or

if (myRes^=nil) then ...

I've never been clear which is more reliable, the handle or pointer.

john calhoun

vrm@blackwater.cerc.wvu.wvnet.edu (Vasile R. Montan) (05/06/91)

I am writing a program which does a lot of reading and writing
of resources (but don't we all? :-).  I am trying to write the
code as defensively as possible, so that if anything goes wrong,
the program will continue as gracefully as possible.  For example,
here is a snip of code from one of my routines:

if OkSoFar then  {If we've run in to no problems so far, then get the}
   begin         {resource and typecast it to the right type.}
    Room := RoomHandle(GetResource('ROOM', RoomNum));
    OSResult := ResError;  {Check for errors.}
    if OSResult <> 0 then  {If there was an error...}
     begin
       doOSErr(OSResult);  {then post an alert}
       OkSoFar := False;   {and stop trying to finish the procedure}
     end;
   end;

As you can see, the soundness of the code relies on ResError to
tell if anything has gone wrong.  However, I tried testing the
code by removing the crucial resource and running this code again.
Even though GetResource couldn'thave found the resource (because
it wasn't there), ResError returned a 0, indicating that nothing
was wrong.  Needless to say, the first time I referred to the
resource, I got a Bus Error exception, because I was following
the invalid handle out into La-La Land.

Why didn't ResError tell me there was a problem?

--Kurisuto
un020070@vaxa.wvnet.edu

resnick@cogsci.uiuc.edu (Pete Resnick) (05/07/91)

vrm@blackwater.cerc.wvu.wvnet.edu (Vasile R. Montan) writes:

>As you can see, the soundness of the code relies on ResError to
>tell if anything has gone wrong.  However, I tried testing the
>code by removing the crucial resource and running this code again.
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As documented, if there is no resource of the type requested when
you make a GetResource call, ResError will return noErr, but the
handle you get back will be nil. On GetResource calls, always check
the handle to see if it was nil. Only use the value of ResError once
you have a nil value to figure out what went wrong.

myHandle = GetResource(myType, myNumber);
if(myHandle == 0L)
     return(ResError() ? ResError() : resNotFound);

That's the way I usually do it.

pr
--
Pete Resnick             (...so what is a mojo, and why would one be rising?)
Graduate assistant - Philosophy Department, Gregory Hall, UIUC
System manager - Cognitive Science Group, Beckman Institute, UIUC
Internet/ARPAnet/EDUnet  : resnick@cogsci.uiuc.edu
BITNET (if no other way) : FREE0285@UIUCVMD

murat@farcomp.UUCP (Murat Konar) (05/07/91)

In article <1696@babcock.cerc.wvu.wvnet.edu> un020070@vaxa.wvnet.edu writes:
[preamble and code frag ommitted]
>As you can see, the soundness of the code relies on ResError to
>tell if anything has gone wrong.  However, I tried testing the
>code by removing the crucial resource and running this code again.
>Even though GetResource couldn'thave found the resource (because
>it wasn't there), ResError returned a 0, indicating that nothing
>was wrong.  Needless to say, the first time I referred to the
>resource, I got a Bus Error exception, because I was following
>the invalid handle out into La-La Land.
>
>Why didn't ResError tell me there was a problem?

Page 119, Inside Macintosh Volume I sez (and I quote):

   Note: If you call GetResource with a resource type that isn't
   in any open resource file, it returns NIL but the ResError 
   function will return the result code noErr.

Neat, huh? I got bit by this before too.

-- 
____________________________________________________________________
Have a day. :^|             
Murat N. Konar	
murat@farcomp.UUCP             -or-          farcomp!murat@apple.com

REEKES@applelink.apple.com (Jim Reekes) (05/08/91)

In article <1991May6.143630.30448@kuhub.cc.ukans.edu>, 2fmlcalls@kuhub.cc.ukans.edu writes:
> 
> > Even though GetResource couldn'thave found the resource (because
> > it wasn't there), ResError returned a 0, indicating that nothing
> > was wrong.  Needless to say, the first time I referred to the
> > resource, I got a Bus Error exception, because I was following
> > the invalid handle out into La-La Land.
> > 
> > Why didn't ResError tell me there was a problem?
> > 
> > --Kurisuto
> > un020070@vaxa.wvnet.edu
> 
> I've seen it documented that ResError doesn't always return 0.  I think the
> preferred method is to check the resource hanfter you read it in.  Check for
> nil.  
> 
> if (myRes = nil) then ....
> 
>   or
> 
> if (myRes^=nil) then ...
> 
> I've never been clear which is more reliable, the handle or pointer.


The handle is the reliable check.  Testing the pointer only tells you if the handle
has been purged, but if you have a nil handle to start with deferencing it will
be bad.  Consider ResError the reason why you got a nil handle.  So, always test for
nil and then look at ResError.  If you are calling AddResource, UpdateResFile, or other
routines that do not return a handle then ResError will be set.  Another gottcha is to
check ResError after calling HGetState.  Otherwise the result is trash, not handle
state information so don't call HSetState with it later.

Jim Reekes E.O., Macintosh Toolbox Engineering

gft_robert@gsbacd.uchicago.edu (opcode ranger) (05/08/91)

In article <13382@goofy.Apple.COM>, REEKES@applelink.apple.com (Jim Reekes) writes:
[...]
>  Another gottcha is to
> check ResError after calling HGetState.  Otherwise the result is trash, not handle
> state information so don't call HSetState with it later.


Check ResError _every_ time you call HGetState, or only on Handles related to
resources?


Robert


-- 
============================================================================
= gft_robert@gsbacd.uchicago.edu * generic disclaimer: * "Good tea.        =
=            		         * all my opinions are *  Nice house."     =
=                                * mine                *  -Worf            =
============================================================================

hairston@henry.ece.cmu.edu (David Hairston) (05/08/91)

[un020070@vaxa.wvnet.edu (Kurisuto) writes:]
[] Even though GetResource couldn'thave found the resource (because
[] it wasn't there), ResError returned a 0, indicating that nothing
[] was wrong.  Needless to say, the first time I referred to the
[] resource, I got a Bus Error exception, because I was following
[] the invalid handle out into La-La Land.
[] 
[] Why didn't ResError tell me there was a problem?

[2fmlcalls@kuhub.cc.ukans.edu writes:]
[] I've seen it documented that ResError doesn't always return 0.  I think the
[] preferred method is to check the resource hanfter you read it in.  Check
[] for nil.  
[] ...
[] I've never been clear which is more reliable, the handle or pointer.

[REEKES@applelink.apple.com (Jim Reekes) writes:]
[] The handle is the reliable check.  Testing the pointer only tells you if
[] the handle has been purged, but if you have a nil handle to start with
[] deferencing it will be bad.  Consider ResError the reason why you got a
[] nil handle.  So, always test for nil and then look at ResError.
[] ...

there's a no-brainer which has worked its way into my code (C example):

#define goodHand(x)    ((x) && *(x))

which gets used for:

realHandle = GetResource(type, index);
if (!goodHand(realHandle))
    ....

as well as for:
fooPointer = NewWindow(...);
if (!goodHand(&fooPointer))
    ....

i guess i shouldn't be lazy but it's a no-brainer ...

  -dave-  
hairston@henry.ece.cmu.edu

ech@cbnewsk.att.com (ned.horvath) (05/08/91)

From article <12946@pt.cs.cmu.edu>, by hairston@henry.ece.cmu.edu (David Hairston):

> there's a no-brainer which has worked its way into my code (C example):

> #define goodHand(x)    ((x) && *(x))
> 
> which gets used for:
> 
> realHandle = GetResource(type, index);
> if (!goodHand(realHandle))
>     ....

Your no-brainer misses two potential problems:

- if I call it with, say, "goodHand (myH++)" (or any other expression
with side-effects) things get ugly (and VERY hard to debug!).

- there is a distinction between handle==NULL and *handle==NULL for
resources: a NULL handle either doesn't exist or hasn't been initialized,
whereas a non-null resource handle which dereferences to a NULL indicates
a purged resource -- call LoadResource to pull the data in.

=Ned Horvath=
-- 

=Ned Horvath=
ehorvath@attmail.com

kaufman@neon.Stanford.EDU (Marc T. Kaufman) (05/08/91)

In article <1991May8.031012.1845@cbnewsk.att.com> ech@cbnewsk.att.com (ned.horvath) writes:
>From article <12946@pt.cs.cmu.edu>, by hairston@henry.ece.cmu.edu (David Hairston):

-> there's a no-brainer which has worked its way into my code (C example):

-> #define goodHand(x)    ((x) && *(x))
 
>- there is a distinction between handle==NULL and *handle==NULL for
>resources: a NULL handle either doesn't exist or hasn't been initialized,
>whereas a non-null resource handle which dereferences to a NULL indicates
>a purged resource -- call LoadResource to pull the data in.

And just to make it worse, *handle won't be NULL for a purged resource,
but StripAddress(*handle) will be.  The purge and resource bits are still
on (at least in 24 bit memory models).

Finally: a use for StripAddress.

Marc Kaufman (kaufman@Neon.stanford.edu)

neeri@iis.ethz.ch (Matthias Ulrich Neeracher) (05/08/91)

In article <1991May8.055136.27101@neon.Stanford.EDU>, kaufman@neon.Stanford.EDU (Marc T. Kaufman) writes:
>And just to make it worse, *handle won't be NULL for a purged resource,
>but StripAddress(*handle) will be.  The purge and resource bits are still
>on (at least in 24 bit memory models).

Are you sure about this ? I'm 99% sure that the purge bit is not set for
purged handles. I don't know about the resource bit, but having seen that
the purge bit gets cleared for purged handles (I think I have seen it !),
I believe that all bits are cleared. Better check this out yourself, though.

Matthias

-- 
Matthias Neeracher                                      neeri@iis.ethz.ch
   "These days, though, you have to be pretty technical before you can 
    even aspire to crudeness." -- William Gibson, _Johnny Mnemonic_

REEKES@applelink.apple.com (Jim Reekes) (05/09/91)

In article <12946@pt.cs.cmu.edu>, hairston@henry.ece.cmu.edu (David Hairston) writes:

> there's a no-brainer which has worked its way into my code (C example):
> 
> #define goodHand(x)    ((x) && *(x))
> 
> which gets used for:
> 
> realHandle = GetResource(type, index);
> if (!goodHand(realHandle))
>     ....
> 
> as well as for:
> fooPointer = NewWindow(...);
> if (!goodHand(&fooPointer))

A problem with goodHand above is that if the GetResource fails, then you
may end up dereferencing a nil address.  It will happen with Pascal's
AND expression, but not with MPW Pascal's &.  It all depends on the language's
implementation.  It's safe to just check on the handle being returned to be
nil.  Besides, calling GetResource will never return a handle that is purged,
unless you set ResLoad to false and the resource isn't in memory.  BUT...
if you set ResLoad to false (which is a valid thing to do) then goodHand
above will always report an error!

I have to correct myself in my original response.

> Another gottcha is to check ResError after calling HGetState.  
> Otherwise the result is trash, not handle state information so 
> don't call HSetState with it later.

I meant to say always check _MemError_ after calling HGetState.

Jim Reekes E.O., Macintosh Toolbox Engineering

pratt@csn.org (Jonathan Pratt) (05/09/91)

In article <13404@goofy.Apple.COM> REEKES@applelink.apple.com (Jim Reekes) writes:
>
>I meant to say always check _MemError_ after calling HGetState.
>
Assuming your program is already debugged, when is this going to give
you anything other than noErr?  IM IV doesn't document what result codes
are possible, but how can you have problems if you call HGetState with
a valid handle?

Jonathan

-- 
/* Jonathan Pratt            Internet: pratt@boulder.colorado.edu  *
 * UCHSC, Box A034           uucp: ..!ncar!boulder!pratt           *
 * 4200 E. Ninth Ave.                                              * 
 * Denver, CO 80262          Phone: (303) 270-7801                 */

pratt@csn.org (Jonathan Pratt) (05/09/91)

In article <1991May8.055136.27101@neon.Stanford.EDU> kaufman@neon.Stanford.EDU (Marc T. Kaufman) writes:
>In article <1991May8.031012.1845@cbnewsk.att.com> ech@cbnewsk.att.com (ned.horvath) writes:
>>From article <12946@pt.cs.cmu.edu>, by hairston@henry.ece.cmu.edu (David Hairston):
>
>-> there's a no-brainer which has worked its way into my code (C example):
>
>-> #define goodHand(x)    ((x) && *(x))
> 
>
>And just to make it worse, *handle won't be NULL for a purged resource,
>but StripAddress(*handle) will be.  The purge and resource bits are still
>on (at least in 24 bit memory models).
>
Come on.  Programming the Mac is enough work without this kind of dis-
information.  Next time get a reference.  From Inside Mac:

	Before attempting to access any purgeable block, you must
	check its handle to make sure the block is still allocated.
	If the handle is empty (that is, h^ = NIL, where h is the
	handle), then the block has been purged; ...

Last I heard, NIL still means zero. :-)

Jonathan

-- 
/* Jonathan Pratt            Internet: pratt@boulder.colorado.edu  *
 * UCHSC, Box A034           uucp: ..!ncar!boulder!pratt           *
 * 4200 E. Ninth Ave.                                              * 
 * Denver, CO 80262          Phone: (303) 270-7801                 */

d88-jwa@byse.nada.kth.se (Jon W{tte) (05/09/91)

In article <13404@goofy.Apple.COM> REEKES@applelink.apple.com (Jim Reekes) writes:

   > #define goodHand(x)    ((x) && *(x))

   A problem with goodHand above is that if the GetResource fails, then you
   may end up dereferencing a nil address.  It will happen with Pascal's
   AND expression, but not with MPW Pascal's &.  It all depends on the
   language's implementation.  It's safe to just check on the handle

Well, the example was in C, and C structly specifies lazy evaluation
of logical expressions (like &&)

   unless you set ResLoad to false and the resource isn't in memory.  BUT...
   if you set ResLoad to false (which is a valid thing to do) then goodHand
   above will always report an error!

If you call SetResLoad(false) you probably know what you do, it's
not a call to call lightly (and certain portions of the OS & toolbox
will fail with SetResLoad(false))

--
						Jon W{tte
						h+@nada.kth.se
						- Power !

time@ice.com (Tim Endres) (05/10/91)

In article <1991May9.040511.26710@colorado.edu>, pratt@csn.org (Jonathan Pratt) writes:
> >And just to make it worse, *handle won't be NULL for a purged resource,
> >but StripAddress(*handle) will be.  The purge and resource bits are still
> >on (at least in 24 bit memory models).
> >
> Come on.  Programming the Mac is enough work without this kind of dis-
> information.  Next time get a reference.  From Inside Mac:
> 
> 	Before attempting to access any purgeable block, you must
> 	check its handle to make sure the block is still allocated.
> 	If the handle is empty (that is, h^ = NIL, where h is the
> 	handle), then the block has been purged; ...
> 
> Last I heard, NIL still means zero. :-)

Actually, the flags for a handle are stored in the *handle*'s address.
Thus, the dereference (* handle) should contain a "pure" address.
Thus, the StripAddress() should only be required on the handle and
*not* on the handle's dereferenced pointer.

tim.

-------------------------------------------------------------
Tim Endres                |  time@ice.com
ICE Engineering           |  uupsi!ice.com!time
8840 Main Street          |  Voice            FAX
Whitmore Lake MI. 48189   |  (313) 449 8288   (313) 449 9208

wysocki@husc9.harvard.edu (Christopher Wysocki) (05/11/91)

In article <1CE00001.falep4@tbomb.ice.com> time@ice.com writes:

>Actually, the flags for a handle are stored in the *handle*'s address.
>Thus, the dereference (* handle) should contain a "pure" address.
>Thus, the StripAddress() should only be required on the handle and
>*not* on the handle's dereferenced pointer.

This is not the case.  With 24-bit addressing, the flag bits for a relocatable 
block are stored in the high byte of the block's master pointer (IM II-25).
In light of this, you definitely *should* call StripAddress for a master
pointer if, for instance, you're comparing the addresses of master pointers.

Chris Wysocki
wysocki@husc9.harvard.edu

Greg@AppleLink.Apple.Com (Greg Marriott) (05/11/91)

In article <1CE00001.falep4@tbomb.ice.com>, time@ice.com (Tim Endres) writes:
> Actually, the flags for a handle are stored in the *handle*'s address.
> Thus, the dereference (* handle) should contain a "pure" address.
> Thus, the StripAddress() should only be required on the handle and
> *not* on the handle's dereferenced pointer.

Sorry, this is dead wrong.  The memory manager stores the flags in the high
byte of the master pointer.  So, (* handle) will contain a "dirty" address
if you're running in 24-bit mode.  In 32-bit mode, the flags are stored
elsewhere.

Greg Marriott
Blue Meanie
Apple Computer, Inc.