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

Arsen Arsenović <[email protected]> Wed, 12 Aug 2026 20:34:59 +0200
Newsgroups gmane.emacs.devel
Message-ID <[email protected]>
Richard Stallman <[email protected]> writes:

>   > Not necessarily, no.  A C99+ program using K&R-exclusive syntax is,
>   > however.
>
> Could you explain precisely what it means, here, to describe a program
> as "a C99+ program"?  I can imagine various possible meanings, and
> that could make a difference here.

A C99 program is a program that complies with rules of the C99 language.

C99+ just means "C99 or later".  The reason this term is often
convenient is because, for the most part, a valid program written for
C99 is valid in C11, ..., and in C23 (though the latter added some
reserved words and changed what an empty parameter list means, so that
is not quite always the case).

Any program passed to a C99 compiler must be a C99 program.

Note that these rules are not only syntactic, there are plenty of
clauses in the language specification that forbid certain run-time
behaviour.

For instance, a program that relies on x + y < x being true when x + y
would overflow is not a correct C99 program, because C99 does not state
what happens when integers overflow, thus there's nothing to support the
above assumption.

> Does Emacs 27 specify an option that implies "reject K&R syntax"
> or "complain about anything that doesn't satisfy the C99 spec?"

Yes, it will specifically pass -std=gnu11 to a C89 compiler:

  /tmp/emacs-27.1$ ./configure CC='gcc -std=gnu89' --with-jpeg=no --with-gif=no
  [...]
    What compiler should emacs be built with?               gcc -std=gnu89 -std=gnu11 -g3 -O2
  [...]

This is fine (though IMO it should pass it unconditionally when the
compiler accepts the flag, and it should be passing -std=gnu99) because
it really should be a valid C11 program, at least in the sense of not
containing K&R-exclusive syntax.

> Does GCC offer an option to allow K&R function definitions along with
> the features of C99, which could have been used in compiling Emacs 27?

Yes, though Emacs 27 doesn't need it, by passing -std=c89.

But, gcc allows you to recover the old behavior (of permitting cetain
K&R constructs in C99 and onwards) also, by passing:

  -Wno-error=implicit-function-declaration
  -Wno-error=declaration-missing-parameter-type
  -Wno-error=return-mismatch
  -Wno-error=int-conversion
  -Wno-error=incompatible-pointer-types

I'm not convinced this suffices to restore compatibility, though.
Mostly because I suspect most of these programs would've also broken
with GCC 13.

> Does GCC offer an option to specify an earlier version of C,
> which might have made the compilation of Emacs 27 work?

Emacs 27 builds fine actually.

The error that was originally being discussed was not a break in the
toolchain, just a system administration error.

>   > >> In reality, the programs have been broken for decades, often in subtle
>   > >> ways, for instance by silently being compiled into wrong code.
>
> This talks of "the programs" and that implies a subtle shift of topic.
> We don't know what those other programs were, and if we knew that,
> we probably wouldn't know any details of their code.

Yes, this pertains to a different topic; I hoped that I made that clear
by writing: "For instance, the example Eli gave, of programs "breaking"
because GCC versions up to 14 failed to properly diagnose invalid C99,
..."

This was in reference to Eli saying: "Old sources will not always easily
compile on a modern system with a new compiler.  For example, AFAIR
latest versions of GCC report errors when they see K&R style function
declarations, and if it's possible to fix that, it requires some obscure
command-line option (I think GCC folks intend to remove it in the
future)"

> So could we please stick to the example we have been discussing: Emacs
> 27.2?  That is a concrete example and we can look at it.
>
> Was Emacs 27.2 being compiled into wrong code
> before that GCC version?  I understand that _some_ programs were,
> but I am asking whether that was actually happening for _this_ program.

ISTM at a glance that Emacs 27.2 works fine.

>   > >> Were we to keep this broken status quo, of having a compiler that fails
>   > >> to diagnose incorrect programs, because people, 20+ years in, were not
>   > >> correcting their habits
>
> With some programs, this may have been a matter of habit.  But not in
> the case of GNU Emacs.
>
> I intentionally kept the C code in Emacs with function definitions in
> K&R syntax for the sake of compilation using old compilers on old
> systems.  Those compilers did not understand C99, and sometimes not
> even C89.  But that did not make it necessary for Emacs to fail with
> them.

GCC still understands C89 when -std=c89 or -std=gnu89 is passed to it.

Though, I do not think, personally, that this flag suffices.  It is very
likely that more work is needed to have true compatibility with some
compiler of that era.  (But, this would've been true with GCC 13 also;
the changes in GCC 14 aren't really that significant)

It'd be good if someone would step up to maintain such support, if there
really is interest in it.

>                                of writing incorrect code?
>
> I refer to the questions above, which bear on the question of whether
> Emacs 27.2 was inherently incorrect.  I think that is crucial.
> If it had an error that gave wrong code all along, I think it was
> indeed incorrect.  But if it didn't give wrong code, I think we should
> conclude that Emacs 27.2 was not incorrect (though some other programs
> with this construct may be incorrect).

There seems to be confusion here.  Emacs 27 is written in "C99 or
later" (configure.ac:856):

  dnl Emacs needs C99 or later.
  gl_PROG_CC_C99

So, the K&R C related discussions are not relevant to it.  They are
relevant to Emacs 23, though.

Emacs 23 did not, in a brief check, appear to me to pass -std=gnu99 or
-std=c99 or whatever other flag, so it is fine in this respect.  In
theory, it should compile with CC='gcc -std=gnu89'.

In reality, at least on my machine, it fails to build because it assumes
some internal details about glibcs FILE:

  ./s/gnu-linux.h:164:10: error: ‘FILE’ has no member named ‘_pptr’
    164 |   ((FILE)->_pptr - (FILE)->_pbase)
        |          ^~
  dispnew.c:88:30: note: in expansion of macro ‘GNU_LIBRARY_PENDING_OUTPUT_COUNT’
     88 | #define PENDING_OUTPUT_COUNT GNU_LIBRARY_PENDING_OUTPUT_COUNT
        |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  dispnew.c:5319:30: note: in expansion of macro ‘PENDING_OUTPUT_COUNT’
   5319 |                   int outq = PENDING_OUTPUT_COUNT (display_output);
        |                              ^~~~~~~~~~~~~~~~~~~~
  ./s/gnu-linux.h:164:26: error: ‘FILE’ has no member named ‘_pbase’
    164 |   ((FILE)->_pptr - (FILE)->_pbase)
        |                          ^~
  dispnew.c:88:30: note: in expansion of macro ‘GNU_LIBRARY_PENDING_OUTPUT_COUNT’
     88 | #define PENDING_OUTPUT_COUNT GNU_LIBRARY_PENDING_OUTPUT_COUNT
        |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  dispnew.c:5319:30: note: in expansion of macro ‘PENDING_OUTPUT_COUNT’
   5319 |                   int outq = PENDING_OUTPUT_COUNT (display_output);
        |                              ^~~~~~~~~~~~~~~~~~~~

... and because it includes termio.h, and because it seems that libpng
broke something, and because the test for NEED_TRADITIONAL seems to be
too optimistic, and some other issues.

I haven't managed to clear all of these (I am short on time), and I see
that there's more based on the Gentoo recipe for Emacs 23:
https://gitweb.gentoo.org/repo/proj/emacs.git/tree/app-editors/emacs/emacs-23.4-r21.ebuild

Emacs 27.2 seems fine, though:

  /tmp/emacs-27.2$ ./src/emacs --batch --eval '(message emacs-version)'
  27.2

>   > >> In my opinion, said habits are a reason to correct the status quo to
>   > >> start diagnosing incorrect code.
>
> Do can you envision what that sounds like to a user of GCC?
>
>   > But, indeed.  Not every K&R C program is incorrect.
>
>   > Here's an example:
>
>   >   ~$ gcc -x c -std=gnu89 - <<<'main(argc, argv) int argc; char **argv; { printf ("%d %s\n", argc, argv[0]); exit (0); }'
>   >   <stdin>: In function ‘main’:
>   >   <stdin>:1:43: warning: incompatible implicit declaration of built-in function ‘printf’ [-Wbuiltin-declaration-mismatch]
>   >   <stdin>:1:1: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
>   >   <stdin>:1:78: warning: incompatible implicit declaration of built-in function ‘exit’ [-Wbuiltin-declaration-mismatch]
>   >   <stdin>:1:1: note: include ‘<stdlib.h>’ or provide a declaration of ‘exit’
>   >   ~$ ./a.out
>   >   1 ./a.out
>   >   ~$ ./a.out 121 3132 12
>   >   4 ./a.out
>   >   ~$
>
> This is example is somewhat of a relief.  It means the GCC developers
> made an effort to continue to allow compilation of programs with K&R
> function definitions.
>
> If Emacs 27.2 had compiled with warnings like that, I'd say it was
> a good outcome.
>
> So I wonder, why was the result failure rather than such warnings.
> Eli, would you like to investigate why?
>
>       ~$ gcc -x c -std=gnu89 - <<<'main(argc, argv) int argc; char **argv; {
> char *x = reallocarray(strdup (argv[0]), 100, 1); printf ("%d %s\n", argc, x);
> exit (0); }'
>
> What is the problem with this one?  Is it that the value of strdup is 64 bits
> and reallocarray's first argument is taken as int?

Yes, the implicit declaration that K&R C specifies for undeclared
functions can easily mismatch what the actual definition is, and indeed
it is incorrect for reallocarray, so it breaks.

This is why the feature was removed: it was extremely error prone.

> This example doesn't load declarations for strdup and reallocarray.
> If the header files for those were included, would that cause correct
> compilation despite the K&R syntax?

Yes.

It is possible to write correct K&R programs.

But, GCC not diagnosing these K&R constructs means that many programs
ended up, by accident, being incorrect programs.
-- 
Arsen Arsenović
signature.asc (application/pgp-signature, 418 B)
-----BEGIN PGP SIGNATURE-----

iQECBAEWCgCqFiEE/uKz0RP8AKMWLWBhUsKUMB6ixJMFAmp8vNMbFIAAAAAABAAO
bWFudTIsMi41KzEuMTIsMiwyXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25z
Lm9wZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXRGRUUyQjNEMTEzRkMwMEEzMTYyRDYw
NjE1MkMyOTQzMDFFQTJDNDkzEBxhcnNlbkBhYXJzZW4ubWUACgkQUsKUMB6ixJNA
RgD/fc13BJcP7tXZ7wXtPriUv8SMQAQBcUbeRAuh6ZrFiioA/0JJMy2/9qVV5Iiy
imMRMtYrG8EGkNYjjp8oMbVxRU4M
=kkjX
-----END PGP SIGNATURE-----