[comp.sys.mac.programmer] Multifinder: how do I patch GetNextEvent?

fjo@ttrdf.UUCP (Frank Owen ) (10/07/88)

   What is the proper way to patch the GetNextEvent() trap for
compatibility with MultiFinder?.  I have created an INIT that
patches this call. The first thing that the patch does is call the
old GetNextEvent, (the one that was there at INIT time.). 
The purpose of the patch is to translate the CapsLock modifier into
the command-key modifier.
   My patch still seems to be in there (the desired result occurs), but 
it introduces long delays and curious behaviour when running under MultiFinder. 
The two specific weird things are :
   1) If I have the Finder as the top window, and then obscure an icon on
      the desktop, then expose it again, the icon  does NOT get redrawn until
      it gets selected again.
   2) While running LightSpeed C's debugger, if I enter an expression in the
      Data window, the watch cursor comes up, and stays there forever,
      UNTIL you mouse-down a few times on another application's window.
      Then when you re-activate the debugger window the expresion in the
      data window is correctly evaluated and displayed.

  I am running from System Tools 5.0. (The first official Multifinder).
All above behaviour ceases if I either remove my INIT, or run without
MultiFinder.

Any ideas?

Frank Owen (..!att!ttrdf!fjo)

-- 
Frank Owen (fjo@ttrdf)  312-982-2182
AT&T Bell Laboratories 
5555 Touhy Ave., Skokie, IL  60077
PATH:  ...!att!ttrdf!fjo

bob@eecs.nwu.edu (Bob Hablutzel) (10/09/88)

>   What is the proper way to patch the GetNextEvent() trap for
> compatibility with MultiFinder?.  I have created an INIT that
> patches this call. The first thing that the patch does is call the
> old GetNextEvent, (the one that was there at INIT time.). 
> The purpose of the patch is to translate the CapsLock modifier into
> the command-key modifier.

- symptoms deleted -
 
> Any ideas?

Ideas are easy. Solutions come harder. :-)

The problem here is that you have written a "tail patch". This is a critter
that does it's work _after_ the original ROM routine. These are verboten, since
some of Apple's patches to the OS rely on the return address of the call.
(I'm not kidding, and for more information why, see a recent issue BYTE which 
had a long article on MultiFinder. Yeah, I said BYTE.)

Try this: there is a low memory global called jGNEFilterProc, or something
real close to that. It is called just before _GetNextEvent returns, with A1
pointing to the event record in question. (At least, this is very close to 
the truth - I'm writting this from memory, without documentation).

Bob Hablutzel		BOB@NUACC.ACNS.NWU.EDU
Disclaimer:		I'd never write a practical joke INIT with this 
			information. Nope. Not me.

jkjl@munnari.oz (John Lim) (10/10/88)

In article <747@ttrdf.UUCP>, fjo@ttrdf.UUCP (Frank Owen ) writes:
> 
>    What is the proper way to patch the GetNextEvent() trap for
> compatibility with MultiFinder?.  I have created an INIT that
> patches this call. The first thing that the patch does is call the
> old GetNextEvent, (the one that was there at INIT time.). 
> 

Have you patched WaitNextEvent. Some programs call WaitNextEvent exclusively,
ignoring GetNextEvent. However WaitNextEvent calls GetNextEvent. This might
cause the timing of the events to go out of synch as described in my message
to lsr@Apple.

	john lim

jln@eecs.nwu.edu (John Norstad) (10/11/88)

>    What is the proper way to patch the GetNextEvent() trap for
> compatibility with MultiFinder?.  I have created an INIT that
> patches this call. The first thing that the patch does is call the
> old GetNextEvent, (the one that was there at INIT time.). 
> The purpose of the patch is to translate the CapsLock modifier into
> the command-key modifier.
>    My patch still seems to be in there (the desired result occurs), but 
> it introduces long delays and curious behaviour when running under MultiFinder. 
> The two specific weird things are :
>    1) If I have the Finder as the top window, and then obscure an icon on
>       the desktop, then expose it again, the icon  does NOT get redrawn until
>       it gets selected again.
>    2) While running LightSpeed C's debugger, if I enter an expression in the
>       Data window, the watch cursor comes up, and stays there forever,
>       UNTIL you mouse-down a few times on another application's window.
>       Then when you re-activate the debugger window the expresion in the
>       data window is correctly evaluated and displayed.
> 
>   I am running from System Tools 5.0. (The first official Multifinder).
> All above behaviour ceases if I either remove my INIT, or run without
> MultiFinder.
> 
> Any ideas?
> 
> Frank Owen (..!att!ttrdf!fjo)

I had exactly the same problem, and posted a note on comp.sys.mac on August 3.
For your edification, here's the relevant part of my earlier note:

I recently patched GetNextEvent, and noticed that under MultiFinder it wasn't
working quite perfectly.  Under MF, when a desktop icon (disk or trash) was
uncovered after a window drag, it wasn't being redrawn.  After much 
investigation I discovered that in this particular circumstance MF was
expecting GetNextEvent to return a full zero word if the function result was
false.  This is much stricter than the usual rule for Boolean values on the
stack, which says that only the low-order bit of the high-order byte of the
word is significant.  The ROM version of GetNextEvent does indeed always 
return a full zero word if the function result is false, but my patch, which
was written in a high-level language, was only setting the high-order byte
of the function result.  I added some in-line assembly language code to clear
the low-order byte, and this fixed the problem.

You should also pay heed to Bob Hablutzel's reply to your note.  These
so-called "tail patches" are frowned upon.  In the case of System 6.0, which
I use, GetNextEvent is not involved in any of the "come from" patches, so it's
OK to write your own tail patch.  But it may break in future releases.

John Norstad
Academic Computing and Network Services
Northwestern University

Bitnet:   JLN@NUACC
Internet: JLN@NUACC.ACNS.NWU.EDU

anson@spray.CalComp.COM (Ed Anson) (10/11/88)

In article <10050022@eecs.nwu.edu> bob@eecs.nwu.edu (Bob Hablutzel) writes:
>>   What is the proper way to patch the GetNextEvent() trap for
>> compatibility with MultiFinder?.  I have created an INIT that
>    [ bunch of stuff deleted ]
>
>The problem here is that you have written a "tail patch". This is a critter
>that does it's work _after_ the original ROM routine. These are verboten, since
>some of Apple's patches to the OS rely on the return address of the call.

I know that tail patches are officially forbidden, but I have written a
successful one for GetNextEvent.

Yes, I know Apple promises they'll maybe break it some day. But today it
works. I'm afraid I missed the original posting, so I don't know what the
the poster's particular problem is.

What I'm still trying to figure out is this: Why does Apple persist in
forbidding a very useful type of patch? Just so they can continue to use
a kludge in their own patches? The necessity of such a proscription has 
still not been explained to my satisfaction.

The opinions expressed above are my own, and not those of my employer. (But
you knew that!)
-- 
=====================================================================
   Ed Anson,    Calcomp Display Products Division,    Hudson NH 03051
   (603) 885-8712,      anson@elrond.CalComp.COM

bob@eecs.nwu.edu (Bob Hablutzel) (10/11/88)

>>>   What is the proper way to patch the GetNextEvent() trap for
>>> compatibility with MultiFinder?.  I have created an INIT that
>>    [ bunch of stuff deleted ]
>>
>>The problem here is that you have written a "tail patch". This is a critter
>>that does it's work _after_ the original ROM routine. These are verboten, since
>>some of Apple's patches to the OS rely on the return address of the call.

>What I'm still trying to figure out is this: Why does Apple persist in
>forbidding a very useful type of patch? Just so they can continue to use
>a kludge in their own patches? The necessity of such a proscription has 
>still not been explained to my satisfaction.


The reason is that the OS is burned into ROMs. ROMs have the annoying 
property of being hard to patch at startup time. Thus, is a bug is found
in the ROM code, Apple is left with two choices:

	1) Patch the entire trap the bug is in.

This is, of course, the best idea, and the reason that _GetTrapAddress
/_SetTrapAddress were originally included in the system. However, there
are cases when the trap to be patched is very large (in terms of ROM code), and
the patch would eat up an equal amount of RAM. This is especially the case
when the bug is in the middle, or toward the end, of large traps. In this
case, route 2 is taken:

	2) Find some small trap called at about the area of the bug in
	   the large trap, and patch this trap to check to see where it's
	   called from, and if it's called from the buggy large trap,
	   do some additional work for the buggy trap (to fix the bug),
	   and maybe even change the return address to bypass the buggy
	   code.

This, needless to say, saves space in RAM, but has the unpleasant side affect
of requiring the trap return address to be constant (remember, we're dealing
with ROM addresses here) for the patch to work. Thus, tail patching will 
cause the patch to fail, and possibly bring back old bugs from the dead.

Bob Hablutzel		BOB@NUACC.ACNS.NWU.EDU
Disclaimer:	Night of the unliving bug. Scary thought, eh?

alexis@ccnysci.UUCP (Alexis Rosen) (10/12/88)

In article <10050024@eecs.nwu.edu> jln@eecs.nwu.edu (John Norstad) writes:
>>    What is the proper way to patch the GetNextEvent() trap for
>> compatibility with MultiFinder?
>> The two specific weird things are :
>>   1) If I have the Finder as the top window, and then obscure an icon on
>>      the desktop, then expose it again, the icon  does NOT get redrawn until
>>      it gets selected again.
>>    2) While running LightSpeed C's debugger, if I enter an expression in the
>>       Data window, the watch cursor comes up, and stays there forever,
>>       UNTIL you mouse-down a few times on another application's window.
>>       Then when you re-activate the debugger window the expresion in the
>>       data window is correctly evaluated and displayed.
>>   I am running from System Tools 5.0. (The first official Multifinder).
>> Frank Owen (..!att!ttrdf!fjo)
>
>I had exactly the same problem, and posted a note on comp.sys.mac on August 3.
>[explains that you need to clear the low-order byte of the returned word]

I missed this when it first came around, but you may be interested to know
that If you try to run MultiFinder 1.0 and System 4.2 with _Finder 5.5_ it
will work properly- except for the bug you just described.

I wonder what Apple is doing in the current Finder that breaks all the rules?
How about tail-patching various file system traps?

It might be amusing to run really old Finders (1.1g, maybe) with MultiFinder
and see just how long they last before dying. (Maybe not too amusing,
especially if they take your hard disk with them...)

----
Alexis Rosen                       {allegra,philabs,cmcl2}!phri\
Writing from                                {harpo,cmcl2}!cucard!dasys1!alexis
The Big Electric Cat                  {portal,well,sun}!hoptoad/
Public UNIX                         Best path: uunet!dasys1!alexis
                                     Or try: alexis@ccnysci.UUCP
                                             alexis@ccnysci.BITNET

anson@spray.CalComp.COM (Ed Anson) (10/12/88)

In article <10050025@eecs.nwu.edu> bob@eecs.nwu.edu (Bob Hablutzel) writes:
>>What I'm still trying to figure out is this: Why does Apple persist in
>>forbidding a very useful type of patch?
>
>The reason is that 
   [very lucid explanation not repeated here.]

Thank you, Bob. Now I understand. But I still don't like it :-(

There are some traps (like GetNextEvent) which are usefully patched at
the end. There are lots of people (like me) who want to accomplish something
that can only be accomplished by tail patching this trap. So our application
works today, but may someday cause strange failures in other areas.

I hope that it's unlikely for GetNextEvent to cause such a problem, because
if it does then my only solution to another problem goes away.

As I understand it (now), the only traps which must not be tail patched are
those which:

1. Are relatively small, and
2. Are called from other (bigger) traps.

Is it thus possible for Apple to classify traps according to these criteria,
and to declare some traps as safe for tail patching? I would hope that
GetNextEvent could be declared safe. Anyone from Apple want to comment on
this issue?

I guess it's unavoidable, but it's still annoying that subtle new rules keep
popping up, documented in obscure places:
1. Avoid tail patches.
2. Call GetNextEvent three or four times before opening a window.
3. Don't use the application events for application events.

These (and possibly other) new rules have broken, or threaten to break,
useful things for me. In some cases, those things were already written
according to the rules in effect at the time. I know that most of these
changes were necessary in some way to make new things work, and I'm willing
to live with that. But I would appreciate it if the impact of some changes
could be reduced. I would rather see the rules modified to something like:
1. Avoid tail patches, except for the following traps...
2. (why is this necessary? sounds like a MultiFinder bug to me!)
3. Reserve one application event to applications, and guarantee that posting
   it will return it to the posting application.

I like to dream. :-)
-- 
=====================================================================
   Ed Anson,    Calcomp Display Products Division,    Hudson NH 03051
   (603) 885-8712,      anson@elrond.CalComp.COM

fjo@ttrdf.UUCP (Frank Owen ) (10/13/88)

in article <2453@spray.CalComp.COM>, anson@spray.CalComp.COM (Ed Anson) says:
> 
> In article <10050022@eecs.nwu.edu> bob@eecs.nwu.edu (Bob Hablutzel) writes:
>>>   What is the proper way to patch the GetNextEvent() trap for
>>> compatibility with MultiFinder?.  I have created an INIT that
>>    [ bunch of stuff deleted ]
>>
>>The problem here is that you have written a "tail patch". This is a critter
>>that does it's work _after_ the original ROM routine. These are verboten, since
>>some of Apple's patches to the OS rely on the return address of the call.
> 
> What I'm still trying to figure out is this: Why does Apple persist in
> forbidding a very useful type of patch? 

  I am the original poster of the GetNextEvent problem.  I have since received
info on this issue. 
   The reason you can't do a tail-patch on GetNextEvent is because Multifinder
uses GNE to do task switching.  Your call to GetNextEvent does not
necessarily return directly to you. When a task switch occurs, the call
to GNE returns to some other application's call to GetNextEvent.
Multifinder's version of GNE apparently needs to identify all the direct callers 
to GNE are, and with a tail patch the caller of Multifinder's GNE is always 
the patch.  This must confuse Multifinder in some way.
  So I guess Apple is quite justified in forbidding this type of patch
in this particuliar case. It let's them do Multifinder.

  Apple is not leaving us without a workaround however. There is this
low-memory global called "jGNEfilter" which points to a filter routine
that GNE will jump to prior to returning. When GNE jumps to this address,
register A1 contains a pointer to the EventRecord.
  I have changed my INIT so that now it no longer patches GetNextEvent,
but rather "inserts" code to be executed just before the jGNEfilter
routine. The address of my code is inserted into the low-memory
global, and when I'm done mangling the EventRecord, my routine jumps to 
the address that had been there prior to my patch. simple. And it works.

  I think tech-note #85 spells out all the rules for this. I don't have
that particuliar note, but if anyone on the net does, I'd appreciatte it
if you'd send me a copy. I'd like to abide by the rules if at all possible.

bye.


-- 
Frank Owen (fjo@ttrdf)  312-982-2182
AT&T Bell Laboratories 
5555 Touhy Ave., Skokie, IL  60077
PATH:  ...!att!ttrdf!fjo

bob@eecs.nwu.edu (Bob Hablutzel) (10/14/88)

> In article <10050025@eecs.nwu.edu> bob@eecs.nwu.edu (Bob Hablutzel) writes:
> >>What I'm still trying to figure out is this: Why does Apple persist in
> >>forbidding a very useful type of patch?
> >
> >The reason is that 
>   [very lucid explanation not repeated here.]
>
> Thank you, Bob. Now I understand. But I still don't like it :-(

You're welcome.

> There are some traps (like GetNextEvent) which are usefully patched at
> the end. There are lots of people (like me) who want to accomplish something
> that can only be accomplished by tail patching this trap. So our application
> works today, but may someday cause strange failures in other areas.

Well, there actually is another way, if you don't mind getting your feet
a little wet (assembler, or at least glue routines).

There exists a low memory global variables jGNEFilter, which, if not nil,
contains the address of a function to call before returning from _GetNextEvent.
_GetNextEvent calls the routines with A1 (I think) pointing to the event
record for the _GetNextEvent call. You can play with this record in any
way you like.

> As I understand it (now), the only traps which must not be tail patched are
> those which:

> 1. Are relatively small, and
> 2. Are called from other (bigger) traps.

This seems right to me, although one can never tell. We may be missing 
something. But, like I say, it seems right.

> Is it thus possible for Apple to classify traps according to these criteria,
> and to declare some traps as safe for tail patching? I would hope that
> GetNextEvent could be declared safe. Anyone from Apple want to comment on
> this issue?

While it may be possible, I doubt Apple will do it. They have to leave 
their options open.

> I guess it's unavoidable, but it's still annoying that subtle new rules keep
> popping up, documented in obscure places:
> 1. Avoid tail patches.
> 2. Call GetNextEvent three or four times before opening a window.
> 3. Don't use the application events for application events.

Did I miss something? I thought the only application event retroactively
nonexistant was APP4. (Personally, I don't know why Apple didn't take
over network events for multifinder events, since network events don't
exist anymore anyhow. Sigh). But, like you say, the documentation is sometimes
obscure. :-)

Bob Hablutzel		BOB@NUACC.ACNS.NWU.EDU

anson@spray.CalComp.COM (Ed Anson) (10/14/88)

In article <749@ttrdf.UUCP> fjo@ttrdf.UUCP (Frank Owen ) writes:
>
>  Apple is not leaving us without a workaround however. There is this
>low-memory global called "jGNEfilter" which points to a filter routine
>that GNE will jump to prior to returning. When GNE jumps to this address,
>register A1 contains a pointer to the EventRecord.

Yes, there is the GNE filter. Yes, TN #85 says how to use it. But NO, Apple
also warns that modifying low-memory globals is dangerous. Even looking at
them is officially discouraged, but permitted "if really necessary".

Another alternative to a tail patch of GNE, is a (permitted) patch of
SystemEvent, which is called by both GNE and WNE after other processing is
completed. I have tried this, and it works well. I can find no reason for
any future compatibility problems. Or is it dangerous to rely on the fact
that this trap gets called under these circumstances, even though it is
documented by Inside Macintosh? :-|
-- 
=====================================================================
   Ed Anson,    Calcomp Display Products Division,    Hudson NH 03051
   (603) 885-8712,      anson@elrond.CalComp.COM

ech@poseidon.ATT.COM (Edward C Horvath) (10/14/88)

In article <10050022@eecs.nwu.edu> bob@eecs.nwu.edu (Bob Hablutzel) writes:
!   What is the proper way to patch the GetNextEvent() trap for
! compatibility with MultiFinder?...

In article <2453@spray.CalComp.COM>, anson@spray.CalComp.COM (Ed Anson) says:
! The problem here is that you have written a "tail patch"...
! forbidding a very useful type of patch? 

From article <749@ttrdf.UUCP>, by fjo@ttrdf.UUCP (Frank Owen ):
! ...There is this
! low-memory global called "jGNEfilter" which points to a filter routine
! that GNE will jump to prior to returning. When GNE jumps to this address,
! register A1 contains a pointer to the EventRecord.
!   I have changed my INIT so that now it no longer patches GetNextEvent,
! but rather "inserts" code to be executed just before the jGNEfilter
! routine. The address of my code is inserted into the low-memory
! global, and when I'm done mangling the EventRecord, my routine jumps to 
! the address that had been there prior to my patch. simple. And it works.

!   I think tech-note #85 spells out all the rules for this. I don't have
! that particuliar note, but if anyone on the net does, I'd appreciatte it
! if you'd send me a copy. I'd like to abide by the rules if at all possible.

You've got it exactly right, Frank: the only detail is to make sure you set
the Boolean result at 4(sp) to TRUE if you replace a null event with one you
created (or to FALSE if you "eat" a non-null event that would otherwise
be returned).

I'll send a copy of TN 85 in the BTL mail; look for it around Christmas...

=Ned Horvath=

brecher@well.UUCP (Steve Brecher) (10/15/88)

In article <2456@spray.CalComp.COM>, anson@spray.CalComp.COM (Ed Anson) writes,
> As I understand it (now), the only traps which must not be tail patched are
> those which:
> 
> 1. Are relatively small, and
> 2. Are called from other (bigger) traps.

Add:
3. Are patched by Apple to fix bugs using "come from" tests.

A "come from" test examines the stack to determine the location of the
caller of the trap, e.g.

    if returnAddress = aParticularROMaddress then
         doSomethingToFixTheROMbug
    else
         jump to original trap code

Apple uses this technique to avoid consuming large amounts of RAM for
ROM bug fixes; in some cases, without "come from" tests, entire managers
would have to be replaced in RAM.

A tail patch wipes out the ROM bug fix patch because the return address
will never satisfy the test, since by definition a tail patch executes
the previous trap code with a JSR.

The wish to
> ...see the rules modified to something like:
> 1. Avoid tail patches, except for the following traps...

cannot be granted by Apple until such time as it discovers how to
write bug-free ROMs, or how to legally protect its operating system
code without resorting to delivering it in ROM.

tim@hoptoad.uucp (Tim Maroney) (10/17/88)

Is there a technical note which refers to this "tail patching" issue?  I must
admit that as a seasoned mac programmer I find the rationales given for the
illegality of tail patching quite incomprehensible.  Whether or not there is
a tail patch would appear to have no effect on the return-address Apple hacks.

Let's look at a case.  Say that GetNamedResource checks the return address
to see if it's being called from a ROM Font Manager routine, and that routine
has a tail patch for some reason.  When the "old" software for the Font
Manager calls the Resource Manager, the return address is exactly what the
Resource Manager "where-from" check expects.  The tail patch has no relevance,
since the "where-from" check is meant only to apply to the way the Resource
Manager is called from that place in the ROM, and that place gets executed
normally.  A tail patch by definition first calls the old trap software.

The problem with non-standard register saving is more serious, since some
software does depend on undocumented register return values.  However, such
code is broken.  If it is a serious problem, your tail patch can as easily
return the same register values once the bug is discovered, but the real
burden of compatibility is on the broken code, not your patch.

Sorry if I'm missing something, but I just can't see how tail patching could
disturb a "where-from" check, and I think third-party developers have to draw
the compatibility line somewhere.  Compatibility with broken software is nice
but not mandatory.
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"As I was walking among the fires of Hell, delighted with the enjoyments of
 Genius; which to Angels look like torment and insanity.  I collected some of
 their Proverbs..." - Blake, "The Marriage of Heaven and Hell"

lsr@Apple.COM (Larry Rosenstein) (10/17/88)

In article <5654@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>
>Let's look at a case.  Say that GetNamedResource checks the return address
>to see if it's being called from a ROM Font Manager routine, and that routine
>has a tail patch for some reason.  When the "old" software for the Font

The problem occurs when there is a tail-patch of GetNamedResource (for
example, in an INIT).  The system patches are installed at boot time, while
the INIT patches are installed afterwards.  

So now the Font Manager calls GetNamedResource which calls the INIT code.
The INIT code calls the original GetNamedResource via a JSR, which leaves
the return address in the INIT code.  This means that the system patch does
not recognize the return address, and the "bug" in the Font Manager is not
fixed.

This assumes that the INIT patch code exits by doing an RTS and returning
the result gotten by the JSR to the old GetNamedResource.  Under this
circumstance, the bug fix code would not be executed.

If it exits by calling the old GetNamedResource again (with the original
parameters), then everything should be fine.  The internal JSR simply
becomes another call to GetNamedResource.  (I don't write system patches,
however, so there may be something else I haven't thought of that makes this
idea wrong.)

Patching the ROM in a "safe" way requires some ingenuity.  Often ones first
idea of how to do it makes some incorrect assumption, or requires a tail
patch.  The trick is to look at the problem from a different point of view,
in order to come up with a solution that works.



		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 46-B  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr

brecher@well.UUCP (Steve Brecher) (10/18/88)

In article <5654@hoptoad.uucp>, tim@hoptoad.uucp (Tim Maroney) writes:
> Whether or not there is a tail patch would appear to have no effect on the
> return-address Apple hacks. ... A tail patch by definition first calls the
> old trap software.

Example:
Let us presume that (hypothetical) ROM routine RsrcMgrTrap is patched by
Apple, and the patch has a "come from" check to see if it is being called
by FontMgrTrap.  The purpose of the RsrcMgrTrap patch is to fix a bug in
FontMgrTrap.  Hence Apple's patch for RsrcMgrTrap would look schematically
like this:

Apple_RsrcMgrTrap_Patch:
    if return_Address = some_ROM_address_In_FontMgrTrap then
         do_Something_To_Fix_The_FontMgrTrap_Bug;
    jump to Original_RsrcMgrTrap_Code

Now I as third-party programmer provide an INIT that patches RsrcMgrTrap
with a tail patch, i.e.,

My_RsrcMgrTrap_Patch:
    Jsr Previous_RsrcMgrTrap ; equivalent to Jsr Apple_RsrcMgrTrap_Patch
    Do_Some_Stuff

FontMgrTrap calls RsrcMgrTrap via an A-line trap instruction which gets
the trap address from the dispatch table.  My_RsrcMgrTrap_Patch is executed.
My patch calls Apple's patch, Apple_RsrcMgrTrap_Patch; that patch sees my
return address, not FontMgrTrap's, on the stack, so the bug in FontMgrTrap
is not fixed.

Note that Apple's patches are installed first (before INITs execute).  In
the process of installing a patch, the installation code gets the old
trap code address via GetTrapAddress, and then installs the new patch
via SetTrapAddress.  The trap dispatch table thus contains the address
of the most recently installed patch.  By adding a tail patch to what is
in effect a linked list of patches, I invalidate any "come from" patches
installed earlier in the list.

darin@Apple.COM (Darin Adler) (10/18/88)

In article <5654@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
> Is there a technical note which refers to this "tail patching" issue?  I must
> admit that as a seasoned mac programmer I find the rationales given for the
> illegality of tail patching quite incomprehensible.  Whether or not there is
> a tail patch would appear to have no effect on the return-address Apple hacks.
> 
> Let's look at a case.  Say that GetNamedResource checks the return address
> to see if it's being called from a ROM Font Manager routine, and that routine
> has a tail patch for some reason.  When the "old" software for the Font
> Manager calls the Resource Manager, the return address is exactly what the
> Resource Manager "where-from" check expects.  The tail patch has no relevance,
> since the "where-from" check is meant only to apply to the way the Resource
> Manager is called from that place in the ROM, and that place gets executed
> normally.  A tail patch by definition first calls the old trap software.

Here's where the problem comes in. The tail patch "by definition" calls the old
trap, but with *a different return address*. The return address is in the
middle of the patch rather than in ROM. This is why it's permissible to do
something first, then call the real trap. In that case the stack is the same
as if the trap had been called directly, with the correct return address.
--
Darin Adler					       AppleLink: Adler4
UUCP: {sun,voder,nsc,mtxinu,dual}!apple!darin	  CSNET: darin@Apple.com

fjo@ttrdf.UUCP (Frank Owen ) (10/18/88)

in article <5654@hoptoad.uucp>, tim@hoptoad.uucp (Tim Maroney) says:
> 
> Let's look at a case.  Say that GetNamedResource checks the return address
> to see if it's being called from a ROM Font Manager routine, and that routine
> has a tail patch for some reason.  When the "old" software for the Font
> Manager calls the Resource Manager, the return address is exactly what the
> Resource Manager "where-from" check expects.  

Bad example. Change it so that you put a tail patch on the
GetNamedResource trap. Now when it checks the return address to see if it's
being called from ROM Font Manager (patched or not) it will discover that
the return address is somewhere in your patch. NOT in the ROM Font Manager,
even if the ROM Font Manager DID make the GetNamedResource call.

Another case. Say that Multifinder's GetNextEvent needs to know who called
it so that it can determine if an application's been getting alot of 
null-events in a row.  Now you put a tail patch on GetNextEvent. 
Well, when Multifinder looks to see who had called it, it always sees your 
patch. It effectively thinks that ALL GetNextEvent calls are coming from the 
same application.

-- 
Frank Owen (fjo@ttrdf)  312-982-2182
AT&T Bell Laboratories 
5555 Touhy Ave., Skokie, IL  60077
PATH:  ...!att!ttrdf!fjo

tim@hoptoad.uucp (Tim Maroney) (10/18/88)

Thanks to Larry Rosenstein for his speedy and clear answer.  (And while I'm
at it, kudos to Apple employees in general for their greatly improved net
support of late!  It used to be that we could count on getting an answer
which was at best curt and often outright rude; now we're practically
guaranteed of a quick, clear, polite answer!)

It seems that what you're saying is that the only safe kind of patch is
one that does its stuff, clears the stack back to the return address, and
then does a JMP.L to the old trap.  Ick.  Most trap patching applications
I've seen or speculated on just can't be done that way.  Could we at least
get a list of "where-from" traps to make things a little less awful?
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"The Diabolonian position is new to the London playgoer of today, but not to
 lovers of serious literature.  From Prometheus to the Wagnerian Siegfried,
 some enemy of the gods, unterrified champion of those oppressed by them, has
 always towered among the heroes of the loftiest poetry."
    - Shaw, "On Diabolonian Ethics"

c60a-1cu@e260-1b.berkeley.edu (Drew Dean) (10/18/88)

Since the reason tail patches break are ROM patches, why doesn't Apple
rewrite the ROMs (with patches from System file applied), and call it
a free upgrade for EVERYONE...Now my SE will magically have 60-100Kb more
RAM (I forget exactly how big the patches are, see a recent MacTutor article).
Of course, if the ROMs are soldered in, this isn't feasible, but if they're
socketed (like they were at one time), why doesn't Apple do something good
for its users and programmers alike...Won't hit the bottom line that much....

Drew Dean
c60a-1cu@web.berkeley.edu
...!ucbvax!web!c60a-1cu

rpd@Apple.COM (Rick Daley) (10/19/88)

In article <5677@hoptoad.uucp>, tim@hoptoad.uucp (Tim Maroney) writes:
> It seems that what you're saying is that the only safe kind of patch is
> one that does its stuff, clears the stack back to the return address, and
> then does a JMP.L to the old trap.  Ick.  Most trap patching applications
> I've seen or speculated on just can't be done that way.  Could we at least
> get a list of "where-from" traps to make things a little less awful?

Sorry, but it's not possible to predict which traps may get come-from
patched in future system releases.  These patches are there to fix bugs,
and there wouldn't be any bugs if we knew where they all were.  There are
only three ways I know of for Apple to fix bugs in ROMs that have already
shipped:
    1) We can use come-from patches that work, but make us forbid
tail-patches.
    2) We can use patches that replace the defective routine, but waste
lots of memory.  New system releases already use up alot of the memory on
a mac plus.
    3) We can send out new ROMs.  Assuming that the bug fixes and new
features would all fit in the mac plus ROMs, this still means someone has
to install them.  If you take your own mac plus apart, and touch the wrong
thing, you will be very dead and unlikely to buy Apple products in the
future.

Basically, the choice is somewhat like voting for the president.  None of
the choices are any good, but some seem to be even worse than others.
Come-from patches seem to be the least of the evils.
					Rick Daley
					rpd@apple.COM
These opinions were actually conveyed to me by each and every Apple employee
and stock holder.

dwb@Apple.COM (David W. Berry) (10/19/88)

In article <5677@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>I've seen or speculated on just can't be done that way.  Could we at least
>get a list of "where-from" traps to make things a little less awful?
	Unfortunately, the list is quite dynamic and changes with every
release of the system.  To publish a list would restrict Apple in making
further changes.  It's an unfortunate fact of life that documenting
something tends to make it permanent.  Witness the memory manager bucky
bits...
>-- 
>Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim


Opinions:  MINE, ALL MINE! (greedy evil chuckle)

David W. Berry
apple!dwb@sun.com	dwb@apple.com	973-5168@408.MaBell

jmpdude@Apple.COM (Mike Puckett) (10/20/88)

I'm sure by now that many people must have responded to your message, but
in case they haven't, I thought I would direct you to read pp. 424-425 in
the first edition of Scott Knaster's "How to Write Macintosh Software."  On
those pages he explains how a tail-patch *can* cause problems.


Mike Puckett
jmpdude@apple.comm

jmunkki@kampi.hut.fi (Juri Munkki) (10/21/88)

In article <18969@apple.Apple.COM> rpd@Apple.COM (Rick Daley) writes:
>In article <5677@hoptoad.uucp>, tim@hoptoad.uucp (Tim Maroney) writes:
>Basically, the choice is somewhat like voting for the president.  None of
>the choices are any good, but some seem to be even worse than others.
>Come-from patches seem to be the least of the evils.

Maybe you need a new candidate?

How about writing the future ROMs so that those large traps actually call
a few subroutines too? All you would need to do to patch the routine is to
change the "main program" and rewrite the buggy subroutine.

I know you can't do this with current ROMs, but I still would prefer
real rewritten traps than those awful tail patches. No wonder the Mac
has gotten so slow, if you do stuff like that. Small traps should not
do any extra stuff, because they should execute as fast as possible.
Traps like GetNextEvent do not have to be fast, because you can't
really guarantee that they'll execute in a known time. Traps like that
should be split into a large number of subroutines.

How about new ROM versions for all machines:

MacPlus:	Remove some ROM resources and put some new stuff in.
MacSE:		Remove the design team pictures and fix the bugs.
		Add as much from the MultiFinder file as possible.
Mac II:		Can you increase the ROM size to 512K?
		Fix bugs, add QuickerGraf, Virtual Memory support.
		Anti-alias Chicago-12 in the cached 8-bit version.

(I know you can't actually do this, but you should think about it.)

_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
|     Juri Munkki jmunkki@hut.fi  jmunkki@fingate.bitnet        I Want   Ne   |
|     Helsinki University of Technology Computing Centre        My Own   XT   |
~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~

P.S.

  I'm in San Fransisco on Thursday November 17th and I have a day off. Would
  anybody be interested to show me Silicon Valley? Since I've practically never
  been in the US, I don't think I'll want to explore too much on my own.

  Anyone from MacTutor or Apple?

  You write to me at:
	Ehrensvardintie 20B8
	00150 Helsinki, Finland

  Or call: +358 0 627 869 (your daytime hours)

  I'll also be at COMDEX, so if there are any interesting events that I should
  attend, please do not hesitate to tell me about them.

  I'm a nice person and a good Macintosh programmer.
  (At least that's what I'm told)
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
|     Juri Munkki jmunkki@hut.fi  jmunkki@fingate.bitnet        I Want   Ne   |
|     Helsinki University of Technology Computing Centre        My Own   XT   |
~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~

fjo@ttrdf.UUCP (Frank Owen ) (10/21/88)

in article <18936@apple.Apple.COM>, darin@Apple.COM (Darin Adler) says:
> ... This is why it's permissible to do
> something first, then call the real trap. In that case the stack is the same
> as if the trap had been called directly, with the correct return address.

Not if you CALL the trap it isn't! You must JUMP to the trap address
upon exit to keep the stack intact.


-- 
Frank Owen (fjo@ttrdf)  312-982-2182
AT&T Bell Laboratories 
5555 Touhy Ave., Skokie, IL  60077
PATH:  ...!att!ttrdf!fjo