Subject: bug#58042: 29.0.50; ASAN use-after-free in re_match_2_internal

From: Gerd Möllmann <[email-masked]>
Date: Sun, 25 Sep 2022 10:28:48 +0200

Eli Zaretskii <[email-masked]> writes:

>> From: Gerd Möllmann <[email-masked]>
>> Cc: [email-masked]
>> Date: Sun, 25 Sep 2022 09:06:59 +0200
>> 
>> Eli Zaretskii <[email-masked]> writes:
>> 
>> >       #14 0x1000f2340 in redisplay_internal xdisp.c:16523
>> >       #15 0x100108f34 in redisplay xdisp.c:16105
>> >
>> > AFAIU, this says that the GC which freed the string data was caused by
>> > safe__call1 inside prepare_menu_bars, which was called from
>> > redisplay_internal.
>> 
>> Ah, okay!  Sorry, I didn't remember that redisplay on the stack.  Please
>> see below.
>> 
>> > Yes, but I have difficulty with the fact that GC was caused by
>> > redisplay, and redisplay cannot be invoked while we are in
>> > re_match_2_internal, AFAIK.  So something else is missing here (or
>> > maybe I'm misinterpreting the ASAN report you posted).
>> 
>> The second and third backtrace that ASAN displays (freed by, and
>> previously allocated) are not backtraces directly involved in the crash.
>> They display some history related to the pointer that causes the crash.
>
> So you are saying that the backtrace I quoted, which shows that GC
> that freed the string was triggered by redisplay, is NOT the GC which
> actually freed the particular string involved in the
> read-from-freed-heap?

That's my working assumption, yes.

> If so, where's the backtrace showing the GC
> that did free/relocate this particular string?

It's not there.

> IOW, I think I'm now confused wrt what exactly the ASAN data tells us.
> Can you perhaps help me understand that, quoting the relevant
> backtraces as you go?

That confueses me, too.

Everything in the hypothesis seems to work, except that I can't explain
how the pointer S.data, to use that term again, can end up pointing into
memory that ASAN has page-protected.

- S must be live at the beginning of the match, otherwise S.data ==
  NULL.

- The freeing of the struct sblock during rediplay happens in the same
  thread as the match where we crash.  So it must have happened before
  the match.

So, the question seems to be what scenario would create a live string
that points into a freed sdata struct.

I'm out of ideas, and close to giving up.  Any alternative theories are
of course more than welcome.  I'm just seeking something that maybe can
be falsified.