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':

Reply via email to