Re: [PATCH] libcpp: Fix up ICE with __VA_OPT__ [PR125048]

Jason Merrill <[email protected]> Wed, 5 Aug 2026 15:58:11 -0400
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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
>