https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123373
Bug ID: 123373
Summary: %R macro does not set arg_going, causing incorrect
token concatenation in specs
Product: gcc
Version: 15.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: [email protected]
Target Milestone: ---
Created attachment 63202
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=63202&action=edit
Set arg_going = 1 after obstack_grow() for %R value.
Outline:
Since GCC 4.1.0 (2005), the Specs Language has
provided the %R macro, which expands to the
sysroot value configured when the compiler was
built.
The expansion is implemented in do_spec_1(),
where %R appends target_system_root and
target_sysroot_suffix to the current obstack
using obstack_grow().
However, unlike other macros that append data
to the obstack (such as %b, %B, %|, %i, and %O),
the %R macro does not set arg_going = 1 after
calling obstack_grow().
This leads to incorrect behavior:
If arg_going is zero, a space following the %R
macro starts a new token without finalizing
the current obstack object via XOBFINISH().
As a result, the next token is concatenated to
the %R expansion, regardless of any spaces
between them.
Reproducer (Ubuntu 24.04 cross compiler)
On Ubuntu 24.04, the aarch64-linux-gnu-gcc
cross compiler is built with:
Configured with: ... --with-sysroot=/ ...
Using the following minimal specs file:
$ cat > spec_with_R <<EOF
*cpp:
%{isysroot=*} %{!isysroot:-isysroot %R} %{pthread:-D_REENTRANT}
EOF
and running:
$ aarch64-linux-gnu-gcc -specs=spec_with_R -E -v hello.c
produces the following cc1 invocation:
... -isysroot /hello.c ...
Here, the %R expansion (/) is incorrectly
concatenated with the next token (hello.c),
producing /hello.c as the argument to -isysroot.
As a result, the correct sysroot (/) is not
searched, and the pathname of the source file
is lost, causing the compiler to wait for
standard input.
Example output:
/usr/libexec/gcc-cross/aarch64-linux-gnu/13/cc1 -E ... -isysroot /hello.c ...
ignoring nonexistent directory "/hello.c/usr/local/include/aarch64-linux-gnu"
ignoring nonexistent directory "/hello.c/usr/include/aarch64-linux-gnu"
ignoring nonexistent directory "/hello.c/usr/include"
Fix:
Since other macros that append to the obstack
set arg_going = 1, the %R macro should do the
same.
Setting arg_going =1 after the obstack_grow()
calls in the %R handler fixes the issue:
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index 4fd87f2c4a1..d17703ee118 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -6819,20 +6819,21 @@ do_spec_1 (const char *spec, int inswitch, const char
*soft_matched_part)
case 'R':
/* We assume there is a directory
separator at the end of this string. */
if (target_system_root)
{
obstack_grow (&obstack, target_system_root,
strlen (target_system_root));
if (target_sysroot_suffix)
obstack_grow (&obstack, target_sysroot_suffix,
strlen (target_sysroot_suffix));
+ arg_going = 1;
}
break;
case 'S':