This is an archive of the discontinued LLVM Phabricator instance.

[clang][deps] Don't share in-memory VFS across scans
ClosedPublic

Authored by jansvoboda11 on Oct 6 2022, 4:56 PM.

Details

Summary

The dependency scanning worker may create an in-memory VFS and inject that into its FileManager. (Implemented in D109485.) This VFS currently persists between scans, which is not correct: in-memory files created in one scan could affect subsequent scans. This patch changes things so that the in-memory VFS is local to DependencyScanningWorker::computeDependencies().

To test this, one would first scan for dependencies of a named module and then run second scan (on the same worker) for something unrelated, which would pick up the in-memory file created in the first scan. This set up is impossible to achieve with clang-scan-deps. We could set this up in ToolingTests, but the scanner needs to access the physical filesystem to store .pcm files. AFAIK we don't have a good way to propagate something like %t into unit tests to make that feasible. (This could be achieved with something like the virtualized OutputManager.)

Diff Detail

Event Timeline

jansvoboda11 created this revision.Oct 6 2022, 4:56 PM
Herald added a project: Restricted Project. · View Herald TranscriptOct 6 2022, 4:56 PM
Herald added a subscriber: ributzka. · View Herald Transcript
jansvoboda11 requested review of this revision.Oct 6 2022, 4:56 PM
Herald added a project: Restricted Project. · View Herald TranscriptOct 6 2022, 4:56 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
This revision is now accepted and ready to land.Oct 12 2022, 5:38 PM
This revision was automatically updated to reflect the committed changes.

Hi @jansvoboda11 , we (Linaro) happen to be one of the few running a bot with threading disabled (for reasons that aren't important here). It has been red a lot lately so you won't have seen the report from it.

https://lab.llvm.org/buildbot/#/builders/178/builds/3045

This does not fail on our other bots and I think LLVM_ENABLE_THREADS=OFF is what breaks it.

From a working build:

$ /home/david.spickett/build-llvm-arm/bin/clang-scan-deps -compilation-database /home/david.spickett/build-llvm-arm-broken/tools/clang/test/ClangScanDeps/Output/modules-full-by-mod-name.cpp.tmp.cdb -j 4 -format experimental-full -mode preprocess-dependency-directives -module-name=header1
Building DependencyScanningWorker
Building DependencyScanningWorker
Building DependencyScanningWorker
Building DependencyScanningWorker
BaseFS was not null
BaseFS was not null
BaseFS moved
BaseFS moved

From a build with no threading:

$ /home/david.spickett/build-llvm-arm-broken/bin/clang-scan-deps -compilation-database /home/david.spickett/build-llvm-arm-broken/tools/clang/test/ClangScanDeps/Output/modules-full-by-mod-name.cpp.tmp.cdb -j 4 -format experimental-full -mode preprocess-dependency-directives -module-name=header1
Building DependencyScanningWorker
BaseFS was not null
BaseFS moved
clang-scan-deps: /home/david.spickett/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp:393: bool clang::tooling::dependencies::DependencyScanningWorker::computeDependencies(llvm::StringRef, const std::vector<std::string> &, clang::tooling::dependencies::DependencyConsumer &, clang::DiagnosticConsumer &, llvm::Optional<StringRef>): Assertion `BaseFS' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: /home/david.spickett/build-llvm-arm-broken/bin/clang-scan-deps -compilation-database /home/david.spickett/build-llvm-arm-broken/tools/clang/test/ClangScanDeps/Output/modules-full-by-mod-name.cpp.tmp.cdb -j 4 -format experimental-full -mode preprocess-dependency-directives -module-name=header1
Aborted (core dumped)

I think I narrowed it down to the move you added (I put a comment on it). When threading is enabled 4 workers are made and so no one tries to use BaseFs after it has been moved from. When only one worker is made, it attempts to use after move BaseFs.

In fact, if you give -j 1 to the threaded version, it also crashes:

$ /home/david.spickett/build-llvm-arm/bin/clang-scan-deps -compilation-database /home/david.spickett/build-llvm-arm-broken/tools/clang/test/Cla
ngScanDeps/Output/modules-full-by-mod-name.cpp.tmp.cdb -j 1 -format experimental-full -mode preprocess-dependency-directives -module-name=header1
Building DependencyScanningWorker
BaseFS was not null
BaseFS moved
clang-scan-deps: /home/david.spickett/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp:393: bool clang::tooling::dependencies::DependencyScanningWorker::computeDependencies(llvm::StringRef, const std::vector<std::string> &, clang::tooling::dependencies::DependencyConsumer &, clang::DiagnosticConsumer &, llvm::Optional<StringRef>): Assertion `BaseFS' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Aborted (core dumped)

I think the same sort of thing would happen if you said -j N+1 when you had N cores? One worker would be run twice? I'm not up on all the details.

So yeah, to reproduce build without threading or add -j 1.

Do you have an idea how this might be handled? If you are moving you clearly want to transfer ownership, but I'm not sure if the BaseFs can just be rebuilt each time. I suppose if N workers can each have a BaseFs, a single worker could recreate it as needed.

Let me know what you think there.

clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
401

This move seems like a problem when only one worker is made.