Bug Summary

File:build/source/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
Warning:line 194, column 7
Address of stack memory associated with temporary object of type '(lambda at /build/source/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h:194:28)' is still referred to by the stack variable 'Controller' upon returning to the caller. This will be a dangling reference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name DependencyScanningTool.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -D CLANG_REPOSITORY_STRING="++20230510111145+7df43bdb42ae-1~exp1~20230510111303.1288" -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/clang/lib/Tooling/DependencyScanning -I /build/source/clang/lib/Tooling/DependencyScanning -I /build/source/clang/include -I tools/clang/include -I include -I /build/source/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp

/build/source/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp

1//===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
10#include "clang/Frontend/Utils.h"
11#include <optional>
12
13using namespace clang;
14using namespace tooling;
15using namespace dependencies;
16
17DependencyScanningTool::DependencyScanningTool(
18 DependencyScanningService &Service,
19 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
20 : Worker(Service, std::move(FS)) {}
21
22namespace {
23/// Prints out all of the gathered dependencies into a string.
24class MakeDependencyPrinterConsumer : public DependencyConsumer {
25public:
26 void handleBuildCommand(Command) override {}
27
28 void
29 handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
30 this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
31 }
32
33 void handleFileDependency(StringRef File) override {
34 Dependencies.push_back(std::string(File));
35 }
36
37 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {
38 // Same as `handleModuleDependency`.
39 }
40
41 void handleModuleDependency(ModuleDeps MD) override {
42 // These are ignored for the make format as it can't support the full
43 // set of deps, and handleFileDependency handles enough for implicitly
44 // built modules to work.
45 }
46
47 void handleContextHash(std::string Hash) override {}
48
49 void printDependencies(std::string &S) {
50 assert(Opts && "Handled dependency output options.")(static_cast <bool> (Opts && "Handled dependency output options."
) ? void (0) : __assert_fail ("Opts && \"Handled dependency output options.\""
, "clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp"
, 50, __extension__ __PRETTY_FUNCTION__))
;
51
52 class DependencyPrinter : public DependencyFileGenerator {
53 public:
54 DependencyPrinter(DependencyOutputOptions &Opts,
55 ArrayRef<std::string> Dependencies)
56 : DependencyFileGenerator(Opts) {
57 for (const auto &Dep : Dependencies)
58 addDependency(Dep);
59 }
60
61 void printDependencies(std::string &S) {
62 llvm::raw_string_ostream OS(S);
63 outputDependencyFile(OS);
64 }
65 };
66
67 DependencyPrinter Generator(*Opts, Dependencies);
68 Generator.printDependencies(S);
69 }
70
71protected:
72 std::unique_ptr<DependencyOutputOptions> Opts;
73 std::vector<std::string> Dependencies;
74};
75} // anonymous namespace
76
77llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
78 const std::vector<std::string> &CommandLine, StringRef CWD) {
79 MakeDependencyPrinterConsumer Consumer;
80 CallbackActionController Controller(nullptr);
1
Calling constructor for 'CallbackActionController'
81 auto Result =
82 Worker.computeDependencies(CWD, CommandLine, Consumer, Controller);
83 if (Result)
84 return std::move(Result);
85 std::string Output;
86 Consumer.printDependencies(Output);
87 return Output;
88}
89
90llvm::Expected<P1689Rule> DependencyScanningTool::getP1689ModuleDependencyFile(
91 const CompileCommand &Command, StringRef CWD, std::string &MakeformatOutput,
92 std::string &MakeformatOutputPath) {
93 class P1689ModuleDependencyPrinterConsumer
94 : public MakeDependencyPrinterConsumer {
95 public:
96 P1689ModuleDependencyPrinterConsumer(P1689Rule &Rule,
97 const CompileCommand &Command)
98 : Filename(Command.Filename), Rule(Rule) {
99 Rule.PrimaryOutput = Command.Output;
100 }
101
102 void handleProvidedAndRequiredStdCXXModules(
103 std::optional<P1689ModuleInfo> Provided,
104 std::vector<P1689ModuleInfo> Requires) override {
105 Rule.Provides = Provided;
106 if (Rule.Provides)
107 Rule.Provides->SourcePath = Filename.str();
108 Rule.Requires = Requires;
109 }
110
111 StringRef getMakeFormatDependencyOutputPath() {
112 if (Opts->OutputFormat != DependencyOutputFormat::Make)
113 return {};
114 return Opts->OutputFile;
115 }
116
117 private:
118 StringRef Filename;
119 P1689Rule &Rule;
120 };
121
122 class P1689ActionController : public DependencyActionController {
123 public:
124 // The lookupModuleOutput is for clang modules. P1689 format don't need it.
125 std::string lookupModuleOutput(const ModuleID &,
126 ModuleOutputKind Kind) override {
127 return "";
128 }
129 };
130
131 P1689Rule Rule;
132 P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command);
133 P1689ActionController Controller;
134 auto Result = Worker.computeDependencies(CWD, Command.CommandLine, Consumer,
135 Controller);
136 if (Result)
137 return std::move(Result);
138
139 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath();
140 if (!MakeformatOutputPath.empty())
141 Consumer.printDependencies(MakeformatOutput);
142 return Rule;
143}
144
145llvm::Expected<TranslationUnitDeps>
146DependencyScanningTool::getTranslationUnitDependencies(
147 const std::vector<std::string> &CommandLine, StringRef CWD,
148 const llvm::StringSet<> &AlreadySeen,
149 LookupModuleOutputCallback LookupModuleOutput) {
150 FullDependencyConsumer Consumer(AlreadySeen);
151 CallbackActionController Controller(LookupModuleOutput);
152 llvm::Error Result =
153 Worker.computeDependencies(CWD, CommandLine, Consumer, Controller);
154 if (Result)
155 return std::move(Result);
156 return Consumer.takeTranslationUnitDeps();
157}
158
159llvm::Expected<ModuleDepsGraph> DependencyScanningTool::getModuleDependencies(
160 StringRef ModuleName, const std::vector<std::string> &CommandLine,
161 StringRef CWD, const llvm::StringSet<> &AlreadySeen,
162 LookupModuleOutputCallback LookupModuleOutput) {
163 FullDependencyConsumer Consumer(AlreadySeen);
164 CallbackActionController Controller(LookupModuleOutput);
165 llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer,
166 Controller, ModuleName);
167 if (Result)
168 return std::move(Result);
169 return Consumer.takeModuleGraphDeps();
170}
171
172TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() {
173 TranslationUnitDeps TU;
174
175 TU.ID.ContextHash = std::move(ContextHash);
176 TU.FileDeps = std::move(Dependencies);
177 TU.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
178 TU.Commands = std::move(Commands);
179
180 for (auto &&M : ClangModuleDeps) {
181 auto &MD = M.second;
182 if (MD.ImportedByMainFile)
183 TU.ClangModuleDeps.push_back(MD.ID);
184 // TODO: Avoid handleModuleDependency even being called for modules
185 // we've already seen.
186 if (AlreadySeen.count(M.first))
187 continue;
188 TU.ModuleGraph.push_back(std::move(MD));
189 }
190
191 return TU;
192}
193
194ModuleDepsGraph FullDependencyConsumer::takeModuleGraphDeps() {
195 ModuleDepsGraph ModuleGraph;
196
197 for (auto &&M : ClangModuleDeps) {
198 auto &MD = M.second;
199 // TODO: Avoid handleModuleDependency even being called for modules
200 // we've already seen.
201 if (AlreadySeen.count(M.first))
202 continue;
203 ModuleGraph.push_back(std::move(MD));
204 }
205
206 return ModuleGraph;
207}
208
209CallbackActionController::~CallbackActionController() {}

/build/source/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h

1//===- DependencyScanningTool.h - clang-scan-deps service -----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGTOOL_H
10#define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGTOOL_H
11
12#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
13#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
14#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
15#include "clang/Tooling/JSONCompilationDatabase.h"
16#include "llvm/ADT/MapVector.h"
17#include "llvm/ADT/StringSet.h"
18#include "llvm/ADT/StringMap.h"
19#include <optional>
20#include <string>
21#include <vector>
22
23namespace clang {
24namespace tooling {
25namespace dependencies {
26
27/// A callback to lookup module outputs for "-fmodule-file=", "-o" etc.
28using LookupModuleOutputCallback =
29 llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>;
30
31/// Graph of modular dependencies.
32using ModuleDepsGraph = std::vector<ModuleDeps>;
33
34/// The full dependencies and module graph for a specific input.
35struct TranslationUnitDeps {
36 /// The graph of direct and transitive modular dependencies.
37 ModuleDepsGraph ModuleGraph;
38
39 /// The identifier of the C++20 module this translation unit exports.
40 ///
41 /// If the translation unit is not a module then \c ID.ModuleName is empty.
42 ModuleID ID;
43
44 /// A collection of absolute paths to files that this translation unit
45 /// directly depends on, not including transitive dependencies.
46 std::vector<std::string> FileDeps;
47
48 /// A collection of prebuilt modules this translation unit directly depends
49 /// on, not including transitive dependencies.
50 std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
51
52 /// A list of modules this translation unit directly depends on, not including
53 /// transitive dependencies.
54 ///
55 /// This may include modules with a different context hash when it can be
56 /// determined that the differences are benign for this compilation.
57 std::vector<ModuleID> ClangModuleDeps;
58
59 /// The sequence of commands required to build the translation unit. Commands
60 /// should be executed in order.
61 ///
62 /// FIXME: If we add support for multi-arch builds in clang-scan-deps, we
63 /// should make the dependencies between commands explicit to enable parallel
64 /// builds of each architecture.
65 std::vector<Command> Commands;
66
67 /// Deprecated driver command-line. This will be removed in a future version.
68 std::vector<std::string> DriverCommandLine;
69};
70
71struct P1689Rule {
72 std::string PrimaryOutput;
73 std::optional<P1689ModuleInfo> Provides;
74 std::vector<P1689ModuleInfo> Requires;
75};
76
77/// The high-level implementation of the dependency discovery tool that runs on
78/// an individual worker thread.
79class DependencyScanningTool {
80public:
81 /// Construct a dependency scanning tool.
82 DependencyScanningTool(DependencyScanningService &Service,
83 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
84 llvm::vfs::createPhysicalFileSystem());
85
86 /// Print out the dependency information into a string using the dependency
87 /// file format that is specified in the options (-MD is the default) and
88 /// return it.
89 ///
90 /// \returns A \c StringError with the diagnostic output if clang errors
91 /// occurred, dependency file contents otherwise.
92 llvm::Expected<std::string>
93 getDependencyFile(const std::vector<std::string> &CommandLine, StringRef CWD);
94
95 /// Collect the module dependency in P1689 format for C++20 named modules.
96 ///
97 /// \param MakeformatOutput The output parameter for dependency information
98 /// in make format if the command line requires to generate make-format
99 /// dependency information by `-MD -MF <dep_file>`.
100 ///
101 /// \param MakeformatOutputPath The output parameter for the path to
102 /// \param MakeformatOutput.
103 ///
104 /// \returns A \c StringError with the diagnostic output if clang errors
105 /// occurred, P1689 dependency format rules otherwise.
106 llvm::Expected<P1689Rule>
107 getP1689ModuleDependencyFile(const clang::tooling::CompileCommand &Command,
108 StringRef CWD, std::string &MakeformatOutput,
109 std::string &MakeformatOutputPath);
110
111 /// Given a Clang driver command-line for a translation unit, gather the
112 /// modular dependencies and return the information needed for explicit build.
113 ///
114 /// \param AlreadySeen This stores modules which have previously been
115 /// reported. Use the same instance for all calls to this
116 /// function for a single \c DependencyScanningTool in a
117 /// single build. Use a different one for different tools,
118 /// and clear it between builds.
119 /// \param LookupModuleOutput This function is called to fill in
120 /// "-fmodule-file=", "-o" and other output
121 /// arguments for dependencies.
122 ///
123 /// \returns a \c StringError with the diagnostic output if clang errors
124 /// occurred, \c TranslationUnitDeps otherwise.
125 llvm::Expected<TranslationUnitDeps>
126 getTranslationUnitDependencies(const std::vector<std::string> &CommandLine,
127 StringRef CWD,
128 const llvm::StringSet<> &AlreadySeen,
129 LookupModuleOutputCallback LookupModuleOutput);
130
131 /// Given a compilation context specified via the Clang driver command-line,
132 /// gather modular dependencies of module with the given name, and return the
133 /// information needed for explicit build.
134 llvm::Expected<ModuleDepsGraph>
135 getModuleDependencies(StringRef ModuleName,
136 const std::vector<std::string> &CommandLine,
137 StringRef CWD, const llvm::StringSet<> &AlreadySeen,
138 LookupModuleOutputCallback LookupModuleOutput);
139
140private:
141 DependencyScanningWorker Worker;
142};
143
144class FullDependencyConsumer : public DependencyConsumer {
145public:
146 FullDependencyConsumer(const llvm::StringSet<> &AlreadySeen)
147 : AlreadySeen(AlreadySeen) {}
148
149 void handleBuildCommand(Command Cmd) override {
150 Commands.push_back(std::move(Cmd));
151 }
152
153 void handleDependencyOutputOpts(const DependencyOutputOptions &) override {}
154
155 void handleFileDependency(StringRef File) override {
156 Dependencies.push_back(std::string(File));
157 }
158
159 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {
160 PrebuiltModuleDeps.emplace_back(std::move(PMD));
161 }
162
163 void handleModuleDependency(ModuleDeps MD) override {
164 ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD);
165 }
166
167 void handleContextHash(std::string Hash) override {
168 ContextHash = std::move(Hash);
169 }
170
171 TranslationUnitDeps takeTranslationUnitDeps();
172 ModuleDepsGraph takeModuleGraphDeps();
173
174private:
175 std::vector<std::string> Dependencies;
176 std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
177 llvm::MapVector<std::string, ModuleDeps, llvm::StringMap<unsigned>>
178 ClangModuleDeps;
179 std::vector<Command> Commands;
180 std::string ContextHash;
181 std::vector<std::string> OutputPaths;
182 const llvm::StringSet<> &AlreadySeen;
183};
184
185/// A simple dependency action controller that uses a callback. If no callback
186/// is provided, it is assumed that looking up module outputs is unreachable.
187class CallbackActionController : public DependencyActionController {
188public:
189 virtual ~CallbackActionController();
190
191 CallbackActionController(LookupModuleOutputCallback LMO)
192 : LookupModuleOutput(std::move(LMO)) {
193 if (!LookupModuleOutput) {
2
Taking true branch
194 LookupModuleOutput = [](const ModuleID &,
3
Address of stack memory associated with temporary object of type '(lambda at /build/source/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h:194:28)' is still referred to by the stack variable 'Controller' upon returning to the caller. This will be a dangling reference
195 ModuleOutputKind) -> std::string {
196 llvm::report_fatal_error("unexpected call to lookupModuleOutput");
197 };
198 }
199 }
200
201 std::string lookupModuleOutput(const ModuleID &ID,
202 ModuleOutputKind Kind) override {
203 return LookupModuleOutput(ID, Kind);
204 }
205
206private:
207 LookupModuleOutputCallback LookupModuleOutput;
208};
209
210} // end namespace dependencies
211} // end namespace tooling
212} // end namespace clang
213
214#endif // LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGTOOL_H