Subject: bug#79156: igc: igc_xpalloc_ambig SEGV

From: Gerd Möllmann <[email-masked]>
Date: Sat, 02 Aug 2025 17:26:59 +0200

We have

igc.c:
 3465 void *
 3466 igc_xpalloc_ambig (void *old_pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min,
 3467                    ptrdiff_t nitems_max, ptrdiff_t item_size)
 3468 {
 3469   ptrdiff_t old_nitems = *nitems;

and igc_xpalloc_ambig is called here with a NULL old_pa, and non-zero
new_size:

charset.c:
 1135           struct charset *new_table =
 1136 #ifdef HAVE_MPS
 1137             igc_xpalloc_ambig
 1138 #else
 1139             xpalloc
 1140 #endif
 1141             (0, &new_size, 1,
 1142              min (INT_MAX, MOST_POSITIVE_FIXNUM),
 1143              sizeof *charset_table);

In this case, this loop deferences a null pointer. 

igc.c:
 3477   mps_word_t *new_word = new_pa;
 3478   for (ptrdiff_t i = 0; i < (old_nitems * item_size) / sizeof (mps_word_t); i++)
 3479     new_word[i] = old_word[i];

This apparently currently never happens in feature/igc, but it could,
and it does when using igc with emacs-mac's mac-win.el which defines
charsets.

Quick workaround is something like

modified   src/igc.c
@@ -3466,7 +3466,7 @@ igc_xfree (void *p)
 igc_xpalloc_ambig (void *old_pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min,
 		   ptrdiff_t nitems_max, ptrdiff_t item_size)
 {
-  ptrdiff_t old_nitems = *nitems;
+  ptrdiff_t old_nitems = old_pa == NULL ? 0 : *nitems;
   ptrdiff_t new_nitems = *nitems;
   ptrdiff_t nbytes = xpalloc_nbytes (old_pa, &new_nitems, nitems_incr_min,
 				     nitems_max, item_size);

Likewise in other igc_xpalloc variants, and one could exploit old_pa ==
NULL, and so on.

If someone else has the time to fix this, that would be nice because I'm
doing something else ATM.