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

From: Pip Cet <[email-masked]>
Date: Thu, 16 Jan 2025 14:54:55 +0000

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

>> The macro that breaks the pattern is STRING_SET_UNIBYTE.  It is
>> confusing.  It confused me.  "STRING_SET_UNIBYTE (string)" does not look
>> like it will change the value of the Lisp_Object string: it looks like
>> it treats the Lisp_Object as a pointer and modifies the string object it
>> points to.  If STRING_SET_UNIBYTE were a function rather than a macro,
>> it couldn't change the value of string.  STRING_SET_MULTIBYTE is a
>> function, and doesn't, and that's even more confusing.  If we want to
>> change string, the universally accepted way of doing that is to pass a
>> pointer to it.
>
> I understand where you are coming from, but after so many years of
> staring at the Emacs code this is very natural to me and doesn't cause
> any confusion.  When I think about these macros, I don't care about
> the differences in their internal workings, whether they modify the
> object or just its guts.

Okay, I think you said that this isn't doesn't cause relevant developers
any confusion.  I disagree, but ultimately it's your decision whom you
consider relevant, so thanks for clarifying that.

I'm not sure about the XSET* macros, FWIW.  They're not type safe
(fixable, to the extent XSETVECTOR can be type-safe):

+#define XSETCONS(a, b) ({ struct Lisp_Cons *c = (b); ((a) = make_lisp_ptr (c, Lisp_Cons)); })
+#define XSETVECTOR(a, b) ({ union vectorlike_header *d = &(b)->header; struct Lisp_Vector *c = (struct Lisp_Vector *)(d); ((a) = make_lisp_ptr (c, Lisp_Vectorlike)); })

That doesn't reveal any bugs, but I don't really see the reason for
their existence at this point.  I suspect the reason was originally to
avoid struct assignment / struct return values, but that's no longer an
issue.  (Another reason may have been avoiding intermediate Lisp_Object
values because they couldn't be GCPRO'd).

If I have a struct Lisp_Cons *, and I want a Lisp_Object, it would feel
natural to me to write

Lisp_Object x = make_lisp_cons (c);

No void *, no lvalue macro arguments, just an ordinary C expression.

Pip