https://gcc.gnu.org/g:d2abcdc5727d0d4e31d6d9d5809aed25818d16a8
commit r16-9507-gd2abcdc5727d0d4e31d6d9d5809aed25818d16a8 Author: Jakub Jelinek <[email protected]> Date: Thu Aug 6 11:01:15 2026 +0200 libcpp: Fix up ICE with __VA_OPT__ [PR125048] 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. 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. 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. Reviewed-by: Jason Merrill <[email protected]> (cherry picked from commit 7b87f41690d46b869c21d0d0537b766698da3827) Diff: --- gcc/testsuite/c-c++-common/cpp/va-opt-11.c | 13 +++++++++++++ libcpp/macro.cc | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/gcc/testsuite/c-c++-common/cpp/va-opt-11.c b/gcc/testsuite/c-c++-common/cpp/va-opt-11.c new file mode 100644 index 000000000000..68cf55817eda --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/va-opt-11.c @@ -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\\\(\\\)\\\)\\\)\\\)\\\)\\\)\\\)\\\)\\\)" } } */ diff --git a/libcpp/macro.cc b/libcpp/macro.cc index c29a34302b63..15260a21b585 100644 --- a/libcpp/macro.cc +++ b/libcpp/macro.cc @@ -1995,6 +1995,7 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, 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_hashnode *node, cpp_macro *macro, 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_hashnode *node, cpp_macro *macro, 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; }
