Subject: corrupting load-in-progress value with "let"

From: Ken Raeburn <[email-masked]>
Date: Tue, 21 Jul 2009 00:01:12 -0400

With these source files:

==> test.el <==
(message "test:  load-in-progress %S" load-in-progress)
(let ((load-path (cons "." load-path)))
   (load "test2"))
(message "test:  load-in-progress %S" load-in-progress)

==> test2.el <==
(message "test2: load-in-progress %S" load-in-progress)
(load "test3")
(message "test2: load-in-progress %S" load-in-progress)

==> test3.el <==
(message "test3: load-in-progress %S" load-in-progress)

and test.el and test2.el byte-compiled but test3.el only present in  
source form, the resulting output shows that load-in-progress is  
inconsistent:

% ./b/Inst/bin/emacs --batch -l test.elc
test:  load-in-progress t
Loading test2...
test2: load-in-progress t
Loading /tmp/emacs-23.0.96/test3.el (source)...
test3: load-in-progress t
test2: load-in-progress t
test:  load-in-progress nil
%

I'm working with the CVS sources and 23.0.96 prerelease code, but can  
reproduce the behavior in 22.1 as shipped with Mac OS X.

The variable load-in-progress is defined in the C code with  
DEFVAR_BOOL applied to an int variable.  Since file loading can be  
invoked recursively, the int value is incremented and decremented when  
loading begins and ends, and should in theory be zero only when no  
file is being loaded.

However, if we're loading a .el file from source, the C code in  
lread.c:Fload calls out to the load-source-file-function, which winds  
up calling code in mule.el, which uses "let" on load-in-progress.  The  
let/unwind support doesn't save and restore the integer value for a  
Lisp_Misc_Boolfwd variable, just the boolean state.  So after loading  
of test3.el finishes above, load-in-progress is restored from its old  
*boolean* value, and gets the value 1 instead of 2 as it should have.   
When test2.elc is done loading, it drops to zero and it looks like  
we're not currently loading any files, even though we're in the middle  
of loading test.elc still.

There is code (in C mode, among others) which checks whether a file is  
being loaded, so this can have a behavioral impact under certain  
conditions.  I haven't actually triggered the problem in my normal  
usage patterns though.

On the assumption that DEFVAR_BOOL variables really ought to just be  
used as booleans (I haven't checked other boolean variables though),  
and we don't want to change the Lisp-visible binding to an integer (or  
"if load-in-progress" would stop working right), I'm working on a  
patch to make load-in-progress an actual boolean, and put the file- 
loading depth counter elsewhere, inaccessible to Lisp (since it's  
inaccessible now).

Ken