Subject: bug#46988: 28.0.50; Documenting and verifying assumptions about C code not calling quit or GCing

From: Pip Cet <[email-masked]>
Date: Mon, 8 Mar 2021 19:57:07 +0000

On Mon, Mar 8, 2021 at 7:42 PM Lars Ingebrigtsen <[email-masked]> wrote:
> Pip Cet <[email-masked]> writes:
>
> > Patch attached. It assumes the standard stack growth direction, and
> > that __builtin_frame_address (0) is available and works. Uses GCC's
> > __attribute__ ((cleanup (...))).
> >
> > My point here is that the technical implementation isn't the problem,
> > the question is whether we're disciplined enough to run with checking
> > enabled and react to bug reports about the fatal error being thrown.
>
> This is something that comes up again and again, so having
> infrastructure to getting feedback faster on this stuff sounds like a
> good idea to me.
>
> Even better would be to have build-time warnings, but I guess that's
> pretty much impossible?

It would be very easy if we could categorize our functions into "don't
call this unless you can accept GC" and "I won't GC", but there's a
third category, "depending on my arguments, I may or may not call GC"
(and, of course, a fourth category, "uncategorized").

It's easy to warn about category 1 functions being called from
category 2 functions, but category 3 ruins everything.

I'm very impressed with gcc's -fanalyzer (in conjunction with -flto)
If you have 20 GB of RAM and 15 minutes to spare, you can get it to
find a few places in the Emacs sources that really do look suspicious
and should be fixed to more obviously not dereference NULL.

Essentially, it does a lot of hard work trying to prove your code is
okay; but, if it can't, it will warn even though it might be (and, in
the case of Emacs, is) wrong.

So "all" we'd have to do is to teach it about some category 1
functions, some category 2 functions, and have it prove there's no
valid control flow from the second to the first. If it can't, we just
might have to accept that our arguments are not obvious enough, and
make them explicit enough for the analyzer to understand.

But I haven't figured out how to do that, yet. My suspicion is the
analyzer works on local variables and ignores the state of global
variables, and our state vars would have to be global.

And I realize I'm poking a hornet's nest, but what this really is is
dynamic scope, which might be easier for the analyzer to grok than
general global variables... hmm.

In summary, I think we can install the run-time check, and when the
analyzer is ready, we'll automatically get compile-time warnings! Even
though it might require a terabyte of RAM!

I also like the way we can build specbind-free dynamic C bindings
using stack structures, global variables, __attribute__((cleanup)),
and some code in unwind_to_catch, but of course that's a GCC extension
and not something we can do outside the realm of debugging.

Pip