Re: Discussion about why GNU/Linux system upgrades cause old programs to break

Arsen Arsenović <[email protected]>
Newsgroups gmane.emacs.devel
Message-ID <[email protected]>
Eli Zaretskii <[email protected]> writes:

>> From: Arsen Arsenović <[email protected]>
>> Cc: [email protected],  [email protected],  [email protected]
>> Date: Thu, 13 Aug 2026 22:43:55 +0200
>> 
>> > First, Emacs 24 was not a C99 program.
>> 
>> Then its build system broken.  It passes -std=gnu99 to the compiler when
>> given a C89 compiler.
>
> It wasn't broken back when Emacs 24.1 was released, or at least we
> weren't aware of that.  It's only the latest GCC releases quite
> arbitrarily decided that -std=gnu99 means to reject any program that
> does not strictly conforms to C99.  Previously, -std=gnu99, unlike
> -std=c99, always allowed useful deviations from the standard.

[Note that -std=c99 and -std=gnu99, with respect to the K&R syntax that
 was moved into -fpermissive in GCC 14, behaved the same, but that's
 besides the point.]

The latter sentence is interesting.  It implies that -std=gnu99 no
longer permits a useful deviation from the standard, but that's simply
not the case.

It no longer permits a certain deviation that was, through experience,
seen to be far more harmful than useful.

ISTM that you've decided that functionality which, as we've seen in wide
experience, in 99/100, if not 999/1000, cases produced problems, not
value, is useful.

How do you make that judgment without having either the broader
experience of building tens of thousands of software releases for
distros, or with dealing with GCC bug reports?

Please do not take that as an insult; I certainly do not mean it in a
derisive way.

But, to make an analogous hypothetical for sake of clarity, if Emacs was
to change some default because you, a veteran Emacs developer, with
consensus from other Emacs developers, saw that it has caused much more
harm than good, and it happened to break some random Elisp script on my
machine, that went untouched for 25 years, but helped a thousand people
for each such script, would you expect me to use it as an example of the
poor judgment, abandonment of principle, carelessness, and adversarial
approach of you, a few years down the line?

Would it be fair for me to say, in that scenario, "that the current
attitude of many/most Emacs developers is at best downplaying the
importance of being able to run old Elisp, and at worst is utterly
hostile to the plight of people who for some reason need to do that"?

I don't read debbugs for Emacs.  I don't maintain ELPA.  I don't
maintain Emacs core.  How could I possibly allow myself to do that?

In the case of the GCC 14 change, the judgment employed very well
could've been mistaken - it was an educated guess - but I've not seen
reason to believe so since.

(Also, to clarify, I don't mean to imply that I'm in the position in
 which you are in the analogous scenario.  In that hypothetical, I'd be
 someone interested in the development of Emacs, and who observes it,
 and contributed some functionality to Emacs, but certainly not someone
 carrying the mantle of a core maintainer.)

I'm sure such things have happened or will happen; they're simply
unavoidable sometimes.

For instance, it may happen when lexical-binding becomes default.

>> > We switched to C99 in Emacs 25.1, see NEWS.25.  So no, the above was
>> > not a violation of the C standard we were adhering to back then,
>> > certainly not a "blatant" violation.  I'm old enough to remember the
>> > old C rules, whereby a function without a prior declaration
>> > (a.k.a. "prototype") had very specific semantics for its return type.
>> 
>> Those semantics are wrong for this case
>
> This case is not necessarily relevant, I was responding to your
> "blatant violation" claim.

What I was referring to there is specifically the lack of declaration as
the blatantly wrong thing.

But, see below for further context - I see now what happened in that
specific case.

>> thereby demonstrating what I said: a program that runs into these
>> errors is very unlikely to be correct.
>
> It was correct at the time Emacs 24.1 was released.

No, a program using the implicit declaration of that function in that
scenario would've been broken, because the function would now probably
be truncating pointers as shown in the reallocarray example.  When Emacs
24.1 was released, the size of ints and pointers were already different
on many machines.

But, that error is not real.. see below.

>> The guessed function declaration has an int return type, as I'm sure you
>> know, but the return type is char*.
>> 
>> This may accidentally work on IP32 machines, but it does not work on any
>> other system, including mine.
>
> That wasn't what happened back when Emacs 24.1 was released, or we
> would have fixed this.  See below.
>
>> > And second, I don't really understand the above warnings at all,
>> > because emacsclient.c in Emacs 24.1 says this starting at line 232,
>> > way before line 1606:
>> >
>> >   char *get_current_dir_name (void);
>> >
>> >   /* Return the current working directory.  Returns NULL on errors.
>> >      Any other returned value must be freed with free.  This is used
>> >      only when get_current_dir_name is not defined on the system.  */
>> >   char*
>> >   get_current_dir_name (void)
>> >   {
>> 
>> That's under a preprocessor condition which, when unmet, also obscures
>> the declaration above it.
>> 
>> When it is unmet, the definition is in another TU and no declaration
>> exists in this TU.
>
> Which probably means glibc changed where this function is declared,
> because the preprocessor condition which hides the prototype was
> supposed to cover the cases where the included header file, where this
> function was expected to be declared, didn't declare it.

No, it didn't.

I see what happened here: recalling my text:

> For instance, attempting to build Emacs 24, I get:
>
>   In file included from ../src/config.h:1430,
>                    from sha256.c:23:
>   ./stdio.h:1030:1: error: ‘gets’ undeclared here (not in a function); did you mean ‘fgets’?
>    1030 | _GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
>         | ^~~~~~~~~~~~~~~
>   In file included from ../src/config.h:1430,
>                    from md5.c:23:
>   ./stdio.h:1030:1: error: ‘gets’ undeclared here (not in a function); did you mean ‘fgets’?
>    1030 | _GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
>         | ^~~~~~~~~~~~~~~
>   In file included from ../src/config.h:1430,
>                    from sha1.c:25:
>   ./stdio.h:1030:1: error: ‘gets’ undeclared here (not in a function); did you mean ‘fgets’?
>    1030 | _GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
>         | ^~~~~~~~~~~~~~~
>   In file included from ../src/config.h:1430,
>                    from sha512.c:23:
>   ./stdio.h:1030:1: error: ‘gets’ undeclared here (not in a function); did you mean ‘fgets’?
>    1030 | _GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
>         | ^~~~~~~~~~~~~~~
>   In file included from ../src/config.h:1430,
>                    from ftoastr.c:28,
>                    from dtoastr.c:2:
>   ./stdio.h:1030:1: error: ‘gets’ undeclared here (not in a function); did you mean ‘fgets’?
>    1030 | _GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
>         | ^~~~~~~~~~~~~~~
> 
> ... and (after fixing that):

The "fixing" that I did was remove _GNU_SOURCE, to allow 'gets' to be
declared.

But, that caused the declaration of get_current_dir_name to go away,
thus the error.

Apologies for that confusion.

>> >> Unfortunately, that's not at all a simple answer, especially not for an
>> >> old codebase.  If I kept attempting to fix the above, I'm sure I'd have
>> >> ran into many more problems.
>> >
>> > I'm sure you would.  And I would naïvely ask: why shouldn't we have an
>> > easily-discoverable option to avoid such problems when we need to
>> > compile old source code?
>> 
>> There's no such thing as an "easily-discoverable option to avoid such
>> problems".
>
> Of course, there is: have the GCC manual include index entries that
> cite the messages emitted by the compiler, or their parts.

Well, no, it's not a discoverability issue.

The GCC 14 change that moved certain K&R C-specific behaviour into
-fpermissive is of course easy to reverse (by passing -fpermissive, for
instance).

But, above, I was not referring to that specific problem, I was talking,
in general, about problems that arise from programs making false
assumptions, which is, as I said, a much bigger class of "breaks" than
the intended breaking changes that were brought up (the K&R C move into
-fpermissive and the change of SIGSTKSZ into a dynamic value when
enabling _GNU_SOURCE).

That'd refer to examples more akin to the one given in
https://lists.gnu.org/archive/html/emacs-devel/2026-08/msg00439.html

Assuming that the incorrect write_4b in that thread ceases to work in
the way the developer thought it ought to at some point, for whatever
reason, there's no way to define a singular flag that could recover it,
because it could fail for a myriad of reasons.

And that's just one example.  There are many such false assumptions all
over all sorts of programs (and I'm sure that some exist in GCC also, of
course).

Thus, there's no real defined semantics that could be encoded into a
massive set of flags, let alone one that's easy to find, to undo those
"breaks".

>> Indeed, but obviously the fewer there are, the fewer breaks happen.
>> 
>> libc has fairly few real breaks, for instance.
>
> It has enough, and the problem here is that glibc is a GNU project, so
> it can be expected that it will avoid breaking Emacs, which is another
> GNU project, at all costs.

I'm not sure that's reasonable to expect indefinitely.

For instance, was 'unexec' not impeding the development of malloc?

Now that we have pdumper, should we still halt malloc development?

I doubt you think that, since you were around when the support for
'unexec' was being removed.

That said, if there was to be some GNU-wide CI system or such that
validated all changes against other GNU packages that are still
considered "supported" (read: tested for by policy and automation),
that'd be very useful for all.

A lot of work, indeed, but other projects do, to my awareness, do such
things.

> Ironically, the MS-Windows C runtime and basic GUI libraries provide
> much better backward compatibility than glibc and other system
> libraries on GNU/Linux do, and that somehow doesn't make me proud.
-- 
Arsen Arsenović
signature.asc (application/pgp-signature, 418 B)
-----BEGIN PGP SIGNATURE-----

iQECBAEWCgCqFiEE/uKz0RP8AKMWLWBhUsKUMB6ixJMFAmqAJvYbFIAAAAAABAAO
bWFudTIsMi41KzEuMTIsMiwyXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25z
Lm9wZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXRGRUUyQjNEMTEzRkMwMEEzMTYyRDYw
NjE1MkMyOTQzMDFFQTJDNDkzEBxhcnNlbkBhYXJzZW4ubWUACgkQUsKUMB6ixJMo
zAEAj9NmXn5DoMMxlWMLwyB8oHVhqDy3WvpoNdDP1fbSI+MA/jgR7azek/nx0CIe
8EiF9+DXbm59u44c/AomBXExWusI
=rC+3
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.