Author: george.karpenkov Date: Fri Sep 28 11:49:21 2018 New Revision: 343352
URL: http://llvm.org/viewvc/llvm-project?rev=343352&view=rev Log: [analyzer] Provide an option to dump generated exploded graphs to a given file. Dumping graphs instead of opening them is often very useful, e.g. for transfer or converting to SVG. Basic sanity check for generated exploded graphs. Differential Revision: https://reviews.llvm.org/D52637 Added: cfe/trunk/test/Analysis/dump_egraph.c Modified: cfe/trunk/include/clang/Driver/CC1Options.td cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/Frontend/CompilerInvocation.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Modified: cfe/trunk/include/clang/Driver/CC1Options.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=343352&r1=343351&r2=343352&view=diff ============================================================================== --- cfe/trunk/include/clang/Driver/CC1Options.td (original) +++ cfe/trunk/include/clang/Driver/CC1Options.td Fri Sep 28 11:49:21 2018 @@ -80,6 +80,9 @@ def trim_egraph : Flag<["-"], "trim-egra HelpText<"Only show error-related paths in the analysis graph">; def analyzer_viz_egraph_graphviz : Flag<["-"], "analyzer-viz-egraph-graphviz">, HelpText<"Display exploded graph using GraphViz">; +def analyzer_dump_egraph : Separate<["-"], "analyzer-dump-egraph">, + HelpText<"Dump exploded graph to the specified file">; +def analyzer_dump_egraph_EQ : Joined<["-"], "analyzer-dump-egraph=">, Alias<analyzer_dump_egraph>; def analyzer_inline_max_stack_depth : Separate<["-"], "analyzer-inline-max-stack-depth">, HelpText<"Bound on stack depth while inlining (4 by default)">; Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h?rev=343352&r1=343351&r2=343352&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h Fri Sep 28 11:49:21 2018 @@ -140,6 +140,9 @@ public: std::string AnalyzeSpecificFunction; + /// File path to which the exploded graph should be dumped. + std::string DumpExplodedGraphTo; + /// Store full compiler invocation for reproducible instructions in the /// generated report. std::string FullCompilerInvocation; Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=343352&r1=343351&r2=343352&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Fri Sep 28 11:49:21 2018 @@ -204,6 +204,18 @@ public: void enqueueEndOfPath(ExplodedNodeSet &S); void GenerateCallExitNode(ExplodedNode *N); + + /// Dump graph to the specified filename. + /// If filename is empty, generate a temporary one. + /// \return The filename the graph is written into. + std::string DumpGraph(bool trim = false, StringRef Filename=""); + + /// Dump the graph consisting of the given nodes to a specified filename. + /// Generate a temporary filename if it's not provided. + /// \return The filename the graph is written into. + std::string DumpGraph(ArrayRef<const ExplodedNode *> Nodes, + StringRef Filename = ""); + /// Visualize the ExplodedGraph created by executing the simulation. void ViewGraph(bool trim = false); Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=343352&r1=343351&r2=343352&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original) +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Fri Sep 28 11:49:21 2018 @@ -284,6 +284,7 @@ static bool ParseAnalyzerArgs(AnalyzerOp Opts.visualizeExplodedGraphWithGraphViz = Args.hasArg(OPT_analyzer_viz_egraph_graphviz); + Opts.DumpExplodedGraphTo = Args.getLastArgValue(OPT_analyzer_dump_egraph); Opts.NoRetryExhausted = Args.hasArg(OPT_analyzer_disable_retry_exhausted); Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=343352&r1=343351&r2=343352&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Fri Sep 28 11:49:21 2018 @@ -3058,6 +3058,23 @@ struct DOTGraphTraits<ExplodedGraph*> : void ExprEngine::ViewGraph(bool trim) { #ifndef NDEBUG + std::string Filename = DumpGraph(trim); + llvm::DisplayGraph(Filename, false, llvm::GraphProgram::DOT); +#endif + llvm::errs() << "Warning: viewing graph requires assertions" << "\n"; +} + + +void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) { +#ifndef NDEBUG + std::string Filename = DumpGraph(Nodes); + llvm::DisplayGraph(Filename, false, llvm::GraphProgram::DOT); +#endif + llvm::errs() << "Warning: viewing graph requires assertions" << "\n"; +} + +std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) { +#ifndef NDEBUG if (trim) { std::vector<const ExplodedNode *> Src; @@ -3067,22 +3084,30 @@ void ExprEngine::ViewGraph(bool trim) { const auto *N = const_cast<ExplodedNode *>(EI->begin()->getErrorNode()); if (N) Src.push_back(N); } - - ViewGraph(Src); + return DumpGraph(Src, Filename); } else { - llvm::ViewGraph(&G, "ExprEngine"); + return llvm::WriteGraph(&G, "ExprEngine", /*ShortNames=*/false, + /*Title=*/"Exploded Graph", /*Filename=*/Filename); } #endif + llvm::errs() << "Warning: dumping graph requires assertions" << "\n"; + return ""; } -void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) { +std::string ExprEngine::DumpGraph(ArrayRef<const ExplodedNode*> Nodes, + StringRef Filename) { #ifndef NDEBUG std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes)); if (!TrimmedG.get()) { llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; } else { - llvm::ViewGraph(TrimmedG.get(), "TrimmedExprEngine"); + return llvm::WriteGraph(TrimmedG.get(), "TrimmedExprEngine", + /*ShortNames=*/false, + /*Title=*/"Trimmed Exploded Graph", + /*Filename=*/Filename); } #endif + llvm::errs() << "Warning: dumping graph requires assertions" << "\n"; + return ""; } Modified: cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp?rev=343352&r1=343351&r2=343352&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Fri Sep 28 11:49:21 2018 @@ -745,6 +745,9 @@ void AnalysisConsumer::ActionExprEngine( Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D), Mgr->options.getMaxNodesPerTopLevelFunction()); + if (!Mgr->options.DumpExplodedGraphTo.empty()) + Eng.DumpGraph(Mgr->options.TrimGraph, Mgr->options.DumpExplodedGraphTo); + // Visualize the exploded graph. if (Mgr->options.visualizeExplodedGraphWithGraphViz) Eng.ViewGraph(Mgr->options.TrimGraph); Added: cfe/trunk/test/Analysis/dump_egraph.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/dump_egraph.c?rev=343352&view=auto ============================================================================== --- cfe/trunk/test/Analysis/dump_egraph.c (added) +++ cfe/trunk/test/Analysis/dump_egraph.c Fri Sep 28 11:49:21 2018 @@ -0,0 +1,15 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-dump-egraph=%t.dot %s +// RUN: cat %t.dot | FileCheck %s +// REQUIRES: asserts + +int getJ(); + +int foo() { + int *x = 0; + return *x; +} + +// CHECK: digraph "Exploded Graph" { +// CHECK: Edge: (B2, B1) +// CHECK: Block Entrance: B1 +// CHECK: Bug report attached _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits