The fix addresses a crash that may happen on Windows machines due to the way
memory pages are allocated.
https://github.com/espressif/esp-idf/issues/12180
Minimal C code to reproduce the issue:
```
/* Compile with -Og. */
#define PIX1(d, s) ((d)[0] = (s)[0])
#define PIX2(d, s) (PIX1 (d, s), (d)[1] = (s)[1])
#define PIX3(d, s) (PIX2 (d, s), (d)[2] = (s)[2])
#define LOOP(N, I) \
for (int y = y0; y < y1; y++) \
for (int x = x0; x < x1; x++) \
{ \
unsigned j = y * stride + x * bpp - off; \
unsigned i = (I) * bpp; \
PIX##N (to + i, from + j); \
} \
n = (x1 - x0) * w * bpp; \
p = to + x0 * w * bpp
#define ROTATE(N) \
switch (mode) \
{ \
case 0: LOOP (N, x * w + y); break; \
case 1: LOOP (N, x * w + w - 1 - y); break; \
case 2: LOOP (N, (h - 1 - x) * w + y); break; \
case 3: LOOP (N, (h - 1 - x) * w + w - 1 - y); break; \
case 4: LOOP (N, y * w + w - 1 - x); break; \
case 5: LOOP (N, (h - 1 - y) * w + x); break; \
case 6: LOOP (N, (h - 1 - y) * w + w - 1 - x); break; \
case 7: LOOP (N, y * w + x); break; \
}
void flush (void *, unsigned);
void
draw (unsigned char *to, const unsigned char *from, int mode, int w, int h,
int bpp, int x0, int y0, int x1, int y1)
{
unsigned stride = (x1 - x0) * bpp;
unsigned off = y0 * stride + x0 * bpp;
unsigned n = 0;
unsigned char *p = to;
if (bpp == 1)
ROTATE (1)
else if (bpp == 2)
ROTATE (2)
else if (bpp == 3)
ROTATE (3)
flush (p, n);
}
```
Running it under Valgrind on Linux confirms the issue:
```
$ valgrind --undef-value-errors=no --redzone-size=4096 \
~/.espressif/tools/xtensa-esp-elf/esp-16.2.0_20260914/xtensa-esp-elf/libexec/gcc/xtensa-esp-elf/16.2.0/cc1
\
-quiet repro.c -Og -o /dev/null
==PID== Invalid read of size 2
==PID== at 0x11205C5: xt_true_regnum(rtx_def*) (in cc1)
==PID== by 0x1120610: xtensa_valid_move(machine_mode, rtx_def**) (in cc1)
==PID== by 0x1121B32: xtensa_emit_move_sequence(rtx_def**, machine_mode) (in
cc1)
==PID== by 0x16C315E: gen_movsi(rtx_def*, rtx_def*) (in cc1)
==PID== by 0x964CF0: emit_move_insn_1(rtx_def*, rtx_def*) (in cc1)
==PID== by 0x96512D: emit_move_insn(rtx_def*, rtx_def*) (in cc1)
==PID== by 0xB7D82F: ??? (in cc1)
==PID== by 0xB7F8FA: ira_emit(bool) (in cc1)
==PID== by 0xB5DDFF: ??? (in cc1)
==PID== by 0xC67237: execute_one_pass(opt_pass*) (in cc1)
==PID== ...
==PID== Address 0x174df6e4 is 146 bytes after a block of size 2,402 alloc'd
==PID== at 0x4846828: malloc (in
/usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==PID== by 0x1A22F7B: xmalloc (in cc1)
==PID== by 0xCEAC2E: resize_reg_info() (in cc1)
==PID== by 0xB5D6E8: ??? (in cc1)
==PID== by 0xC67237: execute_one_pass(opt_pass*) (in cc1)
==PID== ...
==PID==
==PID== Invalid read of size 2
==PID== at 0x11205C5: xt_true_regnum(rtx_def*) (in cc1)
==PID== by 0x1120610: xtensa_valid_move(machine_mode, rtx_def**) (in cc1)
==PID== by 0x192B58C: recog_8(rtx_def*, rtx_insn*, int*) (in cc1)
==PID== by 0xB7D8ED: ??? (in cc1)
==PID== by 0xB7F8FA: ira_emit(bool) (in cc1)
==PID== by 0xB5DDFF: ??? (in cc1)
==PID== by 0xC67237: execute_one_pass(opt_pass*) (in cc1)
==PID== ...
==PID== Address 0x174df6e4 is 146 bytes after a block of size 2,402 alloc'd
==PID== (same allocation stack as above)
==PID==
==PID== ERROR SUMMARY: 210 errors from 2 contexts (suppressed: 0 from 0)
```
The issue can also be reproduced on Windows using the gflags utility:
```
PS C:\Users\qweqe> $gflags = 'C:\Program Files (x86)\Windows
Kits\10\Debuggers\x64\gflags.exe'
PS C:\Users\qweqe> & $gflags /p /enable cc1.exe /full
PS C:\Users\qweqe> & $gflags /p
PS C:\Users\qweqe>
PS C:\Users\qweqe> & $gcc -c "$HOME\rgb601_esp-16.2.0_20260914.i" @f -Og -o
NUL; "driver -Og exit=$LASTEXITCODE"
during RTL pass: ira
/tmp/idf601/components/esp_lcd/rgb/esp_lcd_panel_rgb.c: In function
'rgb_panel_draw_bitmap':
/tmp/idf601/components/esp_lcd/rgb/esp_lcd_panel_rgb.c:741:1: internal compiler
error: Segmentation fault
C:/Users/qweqe/.espressif/tools/xtensa-esp-elf/esp-16.2.0_20260914/xtensa-esp-elf/bin/../libexec/gcc/xtensa-esp-elf/16.2.0/cc1.exe
-fpreprocessed C:\Users\qweqe\rgb601_esp-16.2.0_20260914.i -quiet -dumpbase
NUL.i -dumpbase-ext .i -mdynconfig=xtensa_esp32s3.so -mlongcalls
-mdisable-hardware-atomics -gdwarf-4 -ggdb -Og -std=gnu23 -ffunction-sections
-fdata-sections -fstrict-volatile-bitfields -fno-lto -fno-jump-tables
-fno-tree-switch-conversion -fno-builtin-memcpy -fno-builtin-memset
-fno-builtin-bzero -fzero-init-padding-bits=all -o
C:\Users\qweqe\AppData\Local\Temp\ccVD5s7l.s
Please submit a full bug report, with preprocessed source (by using
-freport-bug).
See <https://gcc.gnu.org/bugs/> for instructions.
driver -Og exit=1
PS C:\Users\qweqe>
```
________________________________
From: Alexey Lapshin
Sent: Tuesday, September 29, 2026 12:00 AM
To: [email protected] <[email protected]>
Cc: [email protected] <[email protected]>; Alexey Gerenkov
<[email protected]>; [email protected]
<[email protected]>; Alexey Lapshin <[email protected]>
Subject: [PATCH] xtensa: Don't index reg_renumber before LRA in xt_true_regnum
xt_true_regnum is used by move expanders and insn conditions, which
IRA invokes through emit_move_insn and recog_memoized when emitting
moves for regional allocation. At that point reg_renumber has not
been resized to cover the new pseudos, so indexing it reads out of
bounds. Before LRA starts reg_renumber holds no final assignments,
so only consult it once LRA is in progress or reload has completed.
gcc/ChangeLog:
* config/xtensa/xtensa.cc (xt_true_regnum): Don't index
reg_renumber before LRA starts.
---
gcc/config/xtensa/xtensa.cc | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc
index 6b5d8d1099a..99a244bf9fd 100644
--- a/gcc/config/xtensa/xtensa.cc
+++ b/gcc/config/xtensa/xtensa.cc
@@ -546,9 +546,12 @@ xt_true_regnum (rtx x)
{
if (REG_P (x))
{
+ /* Before LRA, reg_renumber need not cover pseudos created since it
+ was last resized (e.g. by ira_emit during regional allocation). */
if (! HARD_REGISTER_P (x)
&& reg_renumber
- && (lra_in_progress || reg_renumber[REGNO (x)] >= 0))
+ && (lra_in_progress
+ || (reload_completed && reg_renumber[REGNO (x)] >= 0)))
return reg_renumber[REGNO (x)];
return REGNO (x);
}
--
2.55.0