On 4/29/26 5:20 AM, Jakub Jelinek wrote:
Hi!

The following testcase ICEs, because we call linemap_enter_macro
and remember what it returned and then in a loop sometimes call
vaopt_state::update (src) which can call expand_arg which under the
hood can reallocate the pfile->line_table->info_macro.maps array.
As linemap_enter_macro returns a pointer into that array, if the
array is reallocated, we then dereference the freed memory.

This is a bit worrying about use of linemaps in general, but I guess most places look them up right before use.
The following patch fixes it by remembering the offset into the
pfile->line_table->info_macro.maps array and when we could have called
expand_arg, updates the map variable so that it is correct even after
possible reallocation.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/16.2?

OK.

2026-04-28  Jakub Jelinek  <[email protected]>

        PR preprocessor/125048
        * macro.cc (replace_args): Remember the position of map
        in the pfile->line_table->info_macro.maps array and if vostate
        is DROP, recompute map pointer as expand_arg call could have
        reallocated the pfile->line_table->info_macro.maps array.

        * c-c++-common/cpp/va-opt-11.c: New test.

--- libcpp/macro.cc.jj  2026-03-27 10:17:21.000000000 +0100
+++ libcpp/macro.cc     2026-04-28 11:25:22.767163448 +0200
@@ -1995,6 +1995,7 @@ replace_args (cpp_reader *pfile, cpp_has
    location_t *virt_locs = NULL;
    unsigned int exp_count;
    const line_map_macro *map = NULL;
+  size_t map_idx = 0;
    int track_macro_exp;
/* First, fully macro-expand arguments, calculating the number of
@@ -2105,6 +2106,7 @@ replace_args (cpp_reader *pfile, cpp_has
        map = linemap_enter_macro (pfile->line_table, node,
                                 expansion_point_loc,
                                 num_macro_tokens);
+      map_idx = map - pfile->line_table->info_macro.maps;
      }
    i = 0;
    vaopt_state vaopt_tracker (pfile, macro->variadic, &args[macro->paramc - 
1]);
@@ -2226,6 +2228,11 @@ replace_args (cpp_reader *pfile, cpp_has
                                         NULL, 0);
                }
            }
+         else if (vostate == vaopt_state::DROP && map)
+           /* For the DROP case vaopt_tracker.update (src) can call
+              expand_arg and that can reallocate the maps, so need to
+              update the map pointer.  */
+           map = pfile->line_table->info_macro.maps + map_idx;
          continue;
        }
--- gcc/testsuite/c-c++-common/cpp/va-opt-11.c.jj 2026-04-28 11:34:59.783177007 +0200
+++ gcc/testsuite/c-c++-common/cpp/va-opt-11.c  2026-04-28 11:34:52.220307897 
+0200
@@ -0,0 +1,13 @@
+/* PR preprocessor/125048 */
+/* { dg-do preprocess } */
+/* { dg-options "-std=c23" { target c } } */
+/* { dg-options "-std=c++20" { target c++ } } */
+
+#define A(...)B(B(B(B(__VA_ARGS__##__VA_OPT__()))))
+#define B(...)C(C(C(C(__VA_ARGS__##__VA_OPT__()))))
+#define C(...)D(D(D(D(__VA_ARGS__##__VA_OPT__()))))
+#define D(...)E(E(E(E(__VA_ARGS__##__VA_OPT__()))))
+#define E(...)__VA_ARGS__
+#define F
+A(F)
+/* { dg-final { scan-file va-opt-11.i 
"D\\\(D\\\(D\\\(C\\\(C\\\(C\\\(B\\\(B\\\(B\\\(\\\)\\\)\\\)\\\)\\\)\\\)\\\)\\\)\\\)"
 } } */

        Jakub


Reply via email to