Skip to content

compiler: keep the wrappers out of the compiler's own PATH - #36

Merged
LalitMaganti merged 2 commits into
mainfrom
ccache-loop
Sep 16, 2026
Merged

LalitMaganti merged 2 commits into
mainfrom
ccache-loop

Conversation

@LalitMaganti

@LalitMaganti LalitMaganti commented Sep 16, 2026 •

Copy link
Copy Markdown
Owner

Fixes #26.

The wrapper directory goes on PATH so that the build's clang is this
recorder. ccache is normally used the same way, through a directory of
symlinks named after the compilers, and works out which compiler to run by
looking its own name up on PATH again, skipping only itself. It therefore
finds the wrapper, which hands straight back to ccache, which finds the
wrapper.

ccache's own log, with /usr/lib64/ccache first on PATH:

[69158] Executing /tmp/buildprof-compilers-.../bin/clang ... -E -o .../cpp_stdout.tmp.i hello.c
[69159] Compiler: /tmp/buildprof-compilers-.../bin/clang
[69159] ccache is disabled
[69159] Failed; falling back to running the real compiler
[69159] Executing /tmp/buildprof-compilers-.../bin/clang ... -ftime-trace=.../clang-69159.json
[69159] Failed; falling back to running the real compiler
[69159] Executing ... -ftime-trace=.../clang-69159.json -ftime-trace=.../clang-69159.json

ccache's recursion guard does fire, but its escape hatch is to run the real
compiler in place, and the real compiler is the wrapper again, so the guard
feeds the loop rather than breaking it. Each pass also appends another
-ftime-trace, so the command line grows without bound: over a hundred
copies in one argv after a few seconds, ending in E2BIG rather than an
error anyone can read.

The directory is there to intercept what the build launches, not what the
compiler launches, so take it back out of PATH before handing over. ccache
then resolves clang the way it does without buildprof. The same applies to
distcc and icecream, which pick the compiler the same way.

The wrapper directory goes on PATH so the build's `clang` is this recorder.
ccache is normally used the same way, through a directory of symlinks named
after the compilers, and works out which compiler to run by looking its own
name up on PATH again, skipping only itself. It therefore found the wrapper,
which handed straight back to ccache, which found the wrapper: neither ever
stopped, and each pass appended another `-ftime-trace` to a command line that
grew without bound.

The directory is there to intercept what the build launches, not what the
compiler launches, so take it back out of PATH before handing over.

Fixes #26
The suite requires every tool it names, so the wrapper loop test needs both
present rather than skipped.
@LalitMaganti
LalitMaganti merged commit 66c9ec0 into main Sep 16, 2026
10 of 11 checks passed
LalitMaganti added a commit that referenced this pull request Sep 16, 2026
`main` is red. Installing ccache for the wrapper loop test (#36) put
`/usr/lib/ccache` in front of `cc` on the CI runner, since the Ubuntu
package
populates that directory and the runner already has it on `PATH`. The
build-system diff tests inherit the whole environment, so ccache ran as
part
of every build and each expectation grew a `ccache` node and an
`as -> ccache [.o]` edge.

The expectations describe a plain toolchain, so record with one: take
any
launcher directory off `PATH` for these recordings. Tests that want a
launcher, such as the wrapper loop test, put one there themselves.

Verified on Linux by reproducing the CI condition with
`/usr/lib64/ccache`
first on `PATH`: `make` fails before the change and passes after, and
the
suite is 43 passed, 3 skipped with it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

--compiler-traces loops infinitely if ccache wrappers are in path

1 participant