From: peter@cbmvax.commodore.com (Peter Cherna)
Newsgroups: comp.sys.amiga.programmer
Subject: Re: Problem with the following Code
Date: 16 Oct 92 13:59:39 GMT
Reply-To: peter@cbmvax.commodore.com (Peter Cherna)
Organization: Commodore-Amiga, Inc.  West Chester, PA.

In article <mbs.15lg@adastra.cvl.va.us> mbs@adastra.cvl.va.us (Michael B. Smith) writes:
>            As Gadtools gadgets are not atomic (that is, they are constructed
>            out of multiple standard Intuition gadgets) you can possibly get
>            multiple messages that need to be removed at the Windows UserPort.

That fact has nothing to do with GadTools or its implementation.  The simple
fact of the matter is that messages queue, but signals don't.  That is to
say, if two messages appear before you can process the first one, then
there will be only one signal to wake up your Wait() call.  If you only
process one message per wake-up, then you WILL fall behind.  Simply put,
software must be prepared to handle all possibilities, including:
	- multiple messages for a single signal
	- no message at all resulting from a signal

>>        g = (struct Gadget *)imsg->IAddress;
>
>This is the infamous IAddress bug. You should ONLY assume that the address
>of a gadget is in IAddress if you receive a class of IDCMP_GADGETUP/DOWN.
>This can cause a 80000003 alert on a 68000.

No this is not the bug, and the code shown will not generate the guru 8000 0003
seen on 68000's.  imsg->IAddress is a pointer, and the above code
just copies that pointer, which is ALWAYS a legal operation.  Assuming
the form of the pointer before ascertaining that it's an IDCMP_GADGETUP/DOWN
class is dangerous.  In point of fact, you have to _act_ on the assumption
for there to be a problem.  Casting as a pointer to a Gadget doesn't
actually _do_ anything code-wise, it's still the same memory access.
But dereferencing the pointer before knowing it's a gadget is incorrect.
The following is _dead_wrong_, and sadly common:

	gadgetID = ((struct Gadget *)imsg->IAddress)->GadgetID;

	switch (imsg->Class)
	{
	...
	}

In this example, the programmer is assuming IAddress points at a gadget,
and that he can read the GadgetID member of the structure pointed at,
but IAddress could also be a window or (under 2.04) any arbitrary number.

For clarity, the author of the original code you cite might wish to
write:

	iaddress = imsg->IAddress;

instead of

	g = (struct Gadget *)imsg->IAddress;

Then, down in the switch statement, he'd write:

	case IDCMP_GADGETUP:
	case IDCMP_GADGETDOWN:
	    id = ((struct Gadget *)iaddress)->GadgetID;
	    ...

instead of:

	case IDCMP_GADGETUP:
	case IDCMP_GADGETDOWN:
	    id = g->GadgetID;
	    ...

The two examples generate the same code (and are "bug-free"), but the
form that uses the 'iaddress' variable instead of the 'g' variable
is "more truthful" from a source-code level.  Keeping the quantity
in a variable called 'iaddress' would be good programming practice,
as it serves to remind the programmer that it is not yet ready
for interpretation.

>  //   Michael B. Smith

     Peter
--
Peter Cherna, User Interface Development Group, Commodore-Amiga, Inc.
{uunet|rutgers}!cbmvax!peter    peter@cbmvax.commodore.com
My opinions do not necessarily represent the opinions of my employer.
"I believe it's bad luck to be superstitious."