Subject: Re: bug#63288: 30.0.50; Emacs 30 packages fail to build with native comp on some machines

From: Pip Cet <[email-masked]>
Date: Sat, 25 Jan 2025 20:07:06 +0000

Pip Cet <[email-masked]> writes:

> <[email-masked]> writes:
>
>> To reproduce, I simply have to start `emacs -Q` and eval
>>
>> ```
>> (require 'package)
>> (package-read-from-string "((emacs \"25.1\"))")
>> ```
>> in the scratch buffer:
>>
>> ```
>> Debugger entered--Lisp error: (error "Can’t read whole string")
>>   error("Can't read whole string")
>>   package-read-from-string("((emacs \"25.1\"))")
>>   (progn (package-read-from-string "((emacs \"25.1\"))"))
>>   eval((progn (package-read-from-string "((emacs \"25.1\"))")) t)
>>   elisp--eval-last-sexp(nil)
>> ```
>> Again, after re-evaluating the defun, it's working ok.
>>
>> I found something while messing around with recompiling the file.
>> If I rebuild it manually it works ok, but then rebuilding the whole emacs source tree, and it fails again.
>> So I found this: building with `make -j48` (I have a 24 core CPU) triggers the problem while building
>> with `make -j 1` does not. I attach the build.sh I used to configure the source tree, the configure and
>>  build logs, the elc file with the problem and a good version.
>
> Ouch.  It's known that make -j produces different output sometimes
> (defsubst gets inlined sometimes, sometimes it doesn't), but that's the
> first time I heard about an actual build breaking in identical settings
> depending on it!
>
> No "pure space overflow" message in the logs you sent, so it's probably
> not that.
>
> Few people have 24 cores, so it might just be that that particular
> constellation results in a weird build order.
>
> -(defalias 'package-read-from-string #[257 "\300!\211\242\243\3011\300\"\210\302\303!0\207\210\207" [read-from-string (end-of-file) error "Can't read whole string"] 7 "Read a Lisp expression from STR.\nSignal an error if the entire string was not used.\n\n(fn STR)"])
> +(defalias 'package-read-from-string #[257 "\300!\211\242\243\3011\302\303!0\207\210\207" [read-from-string (end-of-file) error "Can't read whole string"] 6 "Read a Lisp expression from STR.\nSignal an error if the entire string was not used.\n\n(fn STR)"])

(These bytecode objects are incorrect; I was in a comint buffer and ^A,
one of the most common bytecodes, was lost).

The actual disassembly of the correct code is:

byte code for package-read-from-string:
  doc:  Read a Lisp expression from STR. ...
  args: (arg1)
0	constant  read-from-string
1	stack-ref 1
2	call	  1
3	dup
4	car-safe
5	stack-ref 1
6	cdr-safe
7	constant  (end-of-file)
8	pushconditioncase 1
11	constant  read-from-string
12	stack-ref 4
13	stack-ref 2
14	call	  2
15	discard
16	constant  error
17	constant  "Can't read whole string"
18	call	  1
19	pophandler
20	return
21:1	discard
22	stack-ref 1
23	return

That's good and proper and should do the right thing.  The incorrect
code:

0	constant  read-from-string
1	stack-ref 1
2	call	  1
3	dup
4	car-safe
5	stack-ref 1
6	cdr-safe
7	constant  (end-of-file)
8	pushconditioncase 1
11	constant  error
12	constant  "Can't read whole string"
13	call	  1
14	pophandler
15	return
16:1	discard
17	stack-ref 1
18	return

omits the second call to read-string.

Lisp code:

;;;; Inferring package from current buffer
(defun package-read-from-string (str)
  "Read a Lisp expression from STR.
Signal an error if the entire string was not used."
  (pcase-let ((`(,expr . ,offset) (read-from-string str)))
    (condition-case ()
        ;; The call to `ignore' suppresses a compiler warning.
        (progn (ignore (read-from-string str offset))
               (error "Can't read whole string"))
      (end-of-file expr))))

read-from-string is side-effect-free, but not
side-effect-and-error-free.  Both the warning and the compiled code look
like the byte compiler assumed it was the latter.

I tried

(put 'read-from-string 'side-effect-free 'error-free)

and recompiled the Lisp function, and the result was identical to the
bad code.

This could be caused by byte-compile-delete-errors: setting that to t
also produces the incorrect code.

We need to figure out what was compiled in which order.  Can you

ls -lR --full-time

in the "emacs" directory so we get precise timestamps?

Thanks!

Pip