Subject: Re: bug#75581: 30.0.93; Crash when copy-sequence on clear-string'ed multibyte strings with text properties

From: Pip Cet <[email-masked]>
Date: Sun, 19 Jan 2025 11:14:46 +0000

"Eli Zaretskii" <[email-masked]> writes:

>> From: Stefan Kangas <[email-masked]>
>> Date: Sat, 18 Jan 2025 19:14:39 -0600
>> Cc: Pip Cet <[email-masked]>, Richard Stallman <[email-masked]>, [email-masked],
>> 	[email-masked], [email-masked]
>>
>> Eli Zaretskii <[email-masked]> writes:
>>
>> > If we were developing Emacs from scratch today, we would probably use
>> > something simpler.  But we've had those macros for so long, and for
>> > each kind of Lisp object in Emacs, that removing them now would need
>> > to have a very good reason.
>>
>> FTR, I agree that most of these macros should be removed.  It would be a
>> useful simplification of our code.
>>
>> This is not a new idea:
>> https://lists.gnu.org/r/emacs-devel/2024-02/msg00806.html
>> https://lists.gnu.org/r/emacs-devel/2024-03/msg00064.html
>>
>> The counter-argument is "muscle memory" for old-time Emacs hackers.
>> This disregards the complexity and confusion these macros mean for
>> everyone that do not share said muscle memory.
>
> This is a known tension for which there's no good solution except
> asking the newcomers to get used to those macros.  The advantage of
> remembering them is that one can instantly know where to look for some
> problem or aspect of how Emacs internals work.  Removing them is a
> terrible blow; I'm still recovering from the massive overhaul of
> macros in lisp.h done years ago, and have to follow the chain of
> macros and inline functions there too frequently, where previously I
> just _knew_ how a macro works.  By contrast, newcomers will need to
> learn the internals anyway, even if these macros weer removed, it's
> just that their learning curve could perhaps be somewhat less steep,
> because these macros are not hard to understand and the mental model
> of their workings is quite simple.

If there is more than a tiny advantage to removing the macros for new
developers, we should do it: otherwise, we're giving the impression that
the future of Emacs isn't long or significant enough for minor
improvements to be worth it.  Even if we aren't actually convinced this
is true, working on a project is best done in a state of unreasonable
optimism.

I don't think replacing XSETCONS(x,c) by "x = make_lisp_ptr (c,
Lisp_Cons)" is worth it.  Both fail to be type safe and simply convert
any pointer to look like a Lisp_Cons (if you're lucky, and
--enable-checking is in use; if you're not, and you pass an unaligned
char *, you'll get an object with a random Lisp tag; worst case, a
fixnum tag, which would produce a valid but incorrect Lisp_Object).

Who'd ever pass an unaligned char * to XSETCONS, you ask?  alloc.c does
precisely that.  The code depends on !USE_LSB_TAG, so this isn't a bug,
but it's not obvious (to me) that this code will cause an assertion
violation if we run it while USE_LSB_TAG is in use:

  if (val && type != MEM_TYPE_NON_LISP)
    {
      Lisp_Object tem;
      XSETCONS (tem, (char *) val + nbytes - 1);
      if ((char *) XCONS (tem) != (char *) val + nbytes - 1)
	{
	  lisp_malloc_loser = val;
	  free (val);
	  val = 0;
	}
    }

I'd be in favor of:

Lisp_Object lisp_cons (struct Lisp_Cons *)
Lisp_Object lisp_vectorlike (union vectorlike_header *)

While the individual changes (use lowercase; don't modify lval
arguments; drop the "make_" because nothing is made; type safety) aren't
worth it individually, all four of them combined constitute a
significant advantage.

(Maybe we could find a better prefix than lisp_ to indicate that we're
turning a C object into a Lisp_Object)

There is one feature of this that some might consider a problem: type
safety means you cannot pass a "const" pointer to make_lisp_ptr or the
new functions.  This would mean we might have to simplify pdumper.c to
avoid some "const" attributes, and the corresponding casts we use to
remove the attributes.

I think that's *good* because, once no-purespace lands, there are no
more "read-only" Lisp_Objects: there's no flag to say that a cons or
string cannot be written to.  There are plenty of objects you shouldn't
modify, of course, but we never throw an error because we think we
detected such a case. (Two exceptions: hash table mutability and trapped
symbol writes).

Pip