[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: My MACL code crashes under finder, runs ok under multifinder



Sounds like you may have run into a problem we encountered and patched this
last May.  Are you saving and then restarting a dumplisp image, and also using
the foreign function interface?  If so, then your image may crash whenever you
change the way memory is allocated by the system (e.g., by changing from
Finder to Multifinder or the reverse, changing your inits, etc.)

Here's a copy of the bug report, analysis and patch we submitted on 5/31/90:
----------------------------------------------------------------------------
BUG REPORT GQI #2 (Continued): Was "Bad grafPort pointer handling"
Now "CCL::FF-RESTORE-ENVS is deficient and causes MACL crashes"
=================================================================

Thanks to Gary Byers for an earlier response.  After a marathon debugging
session yesterday, I think we finally have the definitive word on what was
happening in and to our MACL 1.3.2 application:

1.  There definitely is a bug in CCL::FF-RESTORE-ENVS (an error of omission
anyway), which causes a fundamental rule of Mac memory management to be
broken.  The fix is easy.  Both the bug and the fix are detailed below.

2.  There is a fatal bug in the 32-bit QuickDraw code in the Mac IIci ROM
which can cause bus errors (i.e., system crashes) with certain legal combina-
tions of arguments to the NewGWorld trap.  This bug is described in detail
in a separate message to be sent to MacDTS and copied to you.

3.  The MACL interface for calling system traps is no longer sufficient now
that the 32-bit QD traps require a selector argument in register D0.  We had
to write C glue routines to be able to call these traps.  It would be nice if
the MACL trap call interface would be extended to handle these D0 selector
calls directly.

ANALYSIS OF BUG IN CCL::FF-RESTORE-ENVS
=======================================

Background on Mac memory management rules:
------------------------------------------
Reference the memory diagram, Fig. 9, in IM-II, page 19, and the Assembly
Language Note on page 20:
	"The location pointed to by A5 will always point to the first Quick-
	Draw global variable."

In other words, A5 points to the high end of the Application Globals and
specifically to a word which contains a pointer to the high end of the Quick-
Draw Globals.  The word at the high end of the QD Globals which is pointed to
thusly is known as "thePort", and contains a pointer to the current grafPort
data structure.

What happens when FF-LOAD is called:
------------------------------------
When FF-LOAD is called to create a foreign function environment (FFENV) it
creates a new Application Globals block along with a jump table, etc., for
use by the foreign functions.  Note specifically that it copies the contents
of the first word of MACL's Application Globals, i.e., a pointer to thePort,
into the first word of the FFENV's Application Globals.  The location of this
first word of the FFENV's Application Globals is saved in the A5PTR slot of an
FFENV-structure which is saved in a list of all FFENV-structures by the Lisp
variable CCL::*FFENVS*.  All is well so far.

What happens when a foreign function is called (during this first execution):
-----------------------------------------------------------------------------
When a foreign function in an FFENV is called, the MACL interface resets A5 to
the value contained in the FFENV-structure's A5PTR slot, and the foreign

function has access to its Application Globals plus shared structures such as
the QD Globals.  Everything works fine.

What happens when DUMPLISP is executed:
---------------------------------------
When DUMPLISP is executed, the functions in the list *SAVE-EXIT-FUNCTIONS* are
executed to clean things up and an image is created which includes the FFENV.
Then the image is effectively reloaded and the functions in the list *RESTORE-
LISP-FUNCTIONS*, including  CCL::FF-RESTORE-ENVS, are executed before returning
control to the toplevel-loop.  Note the following conditions after DUMPLISP has
completed execution:

a.  The FFENVs and all their data structures may have been moved around.  This
is OK, since the new base of the FFENV's Application Globals has been updated
and recorded in the FFENV's A5PTR slot.

b.  There is only one copy of the QD Globals and it hasn't moved.  Thus any
copy of the location of thePort is still valid (FOR THIS EXECUTION OF MACL!!!).
Therefore, the pointers to thePort contained at the base of each FFENV's
Application Globals are OK.

What happens when an image is loaded:
-------------------------------------
This is like the last half of DUMPLISP:  the image is loaded and the functions
in the list *RESTORE-LISP-FUNCTIONS* are executed.  But note the following
conditions now:

a.  The first word of each FFENV's Application Globals is untouched, i.e., they
still contain a pointer the location of thePort which existed when the DUMPLISP
was executed.

b.  But there is no guarantee that the current location of thePort is the same!
Many things can cause it to change: loading another application before MACL
under MultiFinder, changing INITs, changing the buffer size for ATM, etc.
(This was the cause of the curious "aging" phenomenon we saw -- image files
worked for awhile and then started failing).

Now, if the QD Globals and hence thePort are at another location, the first

word of the FFENV's Application Globals DOES NOT POINT at the QD Globals as
specified by IM-II.  The stage is set for disaster. 


What happens when a foreign function is called (starting from an image):
------------------------------------------------------------------------
If the QD Globals and hence thePort are at another location, and the foreign
function does any graphics (i.e., uses the grafPort), anything can happen
including, usually, MACL crashes.

The fix:
========
The fix is simple.  CCL::FF-RESTORE-ENVS needs to simply patch the first word
of each FFENV's Application Globals to point at the correct, current location
of thePort.  Here's a function which can be pushed on the *RESTORE-LISP-
FUNCTIONS* list to do the job until you can fix CCL::FF-RESTORE-ENVS (this fix
is so fundamental that I recommend you incorporate it into CCL::FF-RESTORE-ENVS
rather than have it as a separate entity).

(defconstant $currentA5 #x904)

(defun patch-ffenvs ()  
  (let ((locn-of-thePort (%get-ptr (%get-ptr $currentA5))))
    (dolist (an-ffenv ccl::*ffenvs*)
      (%put-ptr (ccl::ffenv-a5ptr an-ffenv) locn-of-thePort)
      (format t "~&Patched ffenv ~A" (ccl::ffenv-name an-ffenv))

                             ;;; temporary security blanket
      )))


Conclusion:
===========
Sorry to take so long to describe this problem, but we wanted to be absolutely
clear about its cause and its fix.  We also wanted to dissuade you of the
notion that it's not a serious problem, somehow just a lack of documentation
and understanding about what FF-LOAD, etc., do.  As we mentioned before, it's
been like a "nagging toothache" for some time now.  No other user of MACL
should have to go through this again.

Mike Wirth                             Chris Wakefield
mcw@rice.edu (preferred)               D0966@AppleLink
D1542@AppleLink (alternate)