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_viz_egraph_ubigraph : Flag<["-"], "analyzer-viz-egraph-ubigraph">,
- HelpText<"Display exploded graph using Ubigraph">;
def analyzer_inline_max_stack_depth : Separate<["-"], "analyzer-inline-max-stack-depth">,
HelpText<"Bound on stack depth while inlining (4 by default)">;
unsigned TrimGraph : 1;
unsigned visualizeExplodedGraphWithGraphViz : 1;
- unsigned visualizeExplodedGraphWithUbiGraph : 1;
unsigned UnoptimizedCFG : 1;
unsigned PrintStats : 1;
AnalyzerDisplayProgress(false), AnalyzeNestedBlocks(false),
eagerlyAssumeBinOpBifurcation(false), TrimGraph(false),
visualizeExplodedGraphWithGraphViz(false),
- visualizeExplodedGraphWithUbiGraph(false), UnoptimizedCFG(false),
+ UnoptimizedCFG(false),
PrintStats(false), NoRetryExhausted(false), CXXMemberInliningMode() {}
/// Interprets an option's string value as a boolean. The "true" string is
void FlushDiagnostics();
bool shouldVisualize() const {
- return options.visualizeExplodedGraphWithGraphViz ||
- options.visualizeExplodedGraphWithUbiGraph;
+ return options.visualizeExplodedGraphWithGraphViz;
}
bool shouldInlineCall() const {
return const_cast<ExplodedNode*>(this)->succ_end();
}
- // For debugging.
-
-public:
- class Auditor {
- public:
- virtual ~Auditor();
-
- virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst) = 0;
- };
-
- static void SetAuditor(Auditor* A);
-
private:
void replaceSuccessor(ExplodedNode *node) { Succs.replaceNode(node); }
void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); }
Opts.visualizeExplodedGraphWithGraphViz =
Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
- Opts.visualizeExplodedGraphWithUbiGraph =
- Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
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);
using namespace clang;
using namespace ento;
-//===----------------------------------------------------------------------===//
-// Node auditing.
-//===----------------------------------------------------------------------===//
-
-// An out of line virtual method to provide a home for the class vtable.
-ExplodedNode::Auditor::~Auditor() = default;
-
-#ifndef NDEBUG
-static ExplodedNode::Auditor* NodeAuditor = nullptr;
-#endif
-
-void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) {
-#ifndef NDEBUG
- NodeAuditor = A;
-#endif
-}
-
//===----------------------------------------------------------------------===//
// Cleanup.
//===----------------------------------------------------------------------===//
assert(!V->isSink());
Preds.addNode(V, G);
V->Succs.addNode(this, G);
-#ifndef NDEBUG
- if (NodeAuditor) NodeAuditor->AddEdge(V, this);
-#endif
}
void ExplodedNode::NodeGroup::replaceNode(ExplodedNode *node) {
#define DEBUG_TYPE "AnalysisConsumer"
-static std::unique_ptr<ExplodedNode::Auditor> CreateUbiViz();
-
STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
STATISTIC(NumFunctionsAnalyzed,
"The # of functions and blocks analyzed (as top level "
ExprEngine Eng(CTU, *Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries,
IMode);
- // Set the graph auditor.
- std::unique_ptr<ExplodedNode::Auditor> Auditor;
- if (Mgr->options.visualizeExplodedGraphWithUbiGraph) {
- Auditor = CreateUbiViz();
- ExplodedNode::SetAuditor(Auditor.get());
- }
-
// Execute the worklist algorithm.
Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
Mgr->options.getMaxNodesPerTopLevelFunction());
- // Release the auditor (if any) so that it doesn't monitor the graph
- // created BugReporter.
- ExplodedNode::SetAuditor(nullptr);
-
// Visualize the exploded graph.
if (Mgr->options.visualizeExplodedGraphWithGraphViz)
Eng.ViewGraph(Mgr->options.TrimGraph);
CI.getFrontendOpts().Plugins,
hasModelPath ? new ModelInjector(CI) : nullptr);
}
-
-//===----------------------------------------------------------------------===//
-// Ubigraph Visualization. FIXME: Move to separate file.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class UbigraphViz : public ExplodedNode::Auditor {
- std::unique_ptr<raw_ostream> Out;
- std::string Filename;
- unsigned Cntr;
-
- typedef llvm::DenseMap<void*,unsigned> VMap;
- VMap M;
-
-public:
- UbigraphViz(std::unique_ptr<raw_ostream> Out, StringRef Filename);
-
- ~UbigraphViz() override;
-
- void AddEdge(ExplodedNode *Src, ExplodedNode *Dst) override;
-};
-
-} // end anonymous namespace
-
-static std::unique_ptr<ExplodedNode::Auditor> CreateUbiViz() {
- SmallString<128> P;
- int FD;
- llvm::sys::fs::createTemporaryFile("llvm_ubi", "", FD, P);
- llvm::errs() << "Writing '" << P << "'.\n";
-
- auto Stream = llvm::make_unique<llvm::raw_fd_ostream>(FD, true);
-
- return llvm::make_unique<UbigraphViz>(std::move(Stream), P);
-}
-
-void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
-
- assert (Src != Dst && "Self-edges are not allowed.");
-
- // Lookup the Src. If it is a new node, it's a root.
- VMap::iterator SrcI= M.find(Src);
- unsigned SrcID;
-
- if (SrcI == M.end()) {
- M[Src] = SrcID = Cntr++;
- *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
- }
- else
- SrcID = SrcI->second;
-
- // Lookup the Dst.
- VMap::iterator DstI= M.find(Dst);
- unsigned DstID;
-
- if (DstI == M.end()) {
- M[Dst] = DstID = Cntr++;
- *Out << "('vertex', " << DstID << ")\n";
- }
- else {
- // We have hit DstID before. Change its style to reflect a cache hit.
- DstID = DstI->second;
- *Out << "('change_vertex_style', " << DstID << ", 1)\n";
- }
-
- // Add the edge.
- *Out << "('edge', " << SrcID << ", " << DstID
- << ", ('arrow','true'), ('oriented', 'true'))\n";
-}
-
-UbigraphViz::UbigraphViz(std::unique_ptr<raw_ostream> OutStream,
- StringRef Filename)
- : Out(std::move(OutStream)), Filename(Filename), Cntr(0) {
-
- *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
- *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
- " ('size', '1.5'))\n";
-}
-
-UbigraphViz::~UbigraphViz() {
- Out.reset();
- llvm::errs() << "Running 'ubiviz' program... ";
- std::string ErrMsg;
- std::string Ubiviz;
- if (auto Path = llvm::sys::findProgramByName("ubiviz"))
- Ubiviz = *Path;
- std::array<StringRef, 2> Args{{Ubiviz, Filename}};
-
- if (llvm::sys::ExecuteAndWait(Ubiviz, Args, llvm::None, {}, 0, 0, &ErrMsg)) {
- llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
- }
-
- // Delete the file.
- llvm::sys::fs::remove(Filename);
-}
+++ /dev/null
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.API -analyzer-viz-egraph-ubigraph -verify %s
-// expected-no-diagnostics
-
-int f(int x) {
- return x < 0 ? 0 : 42;
-}
-
if args.disable_checker:
checkers = ','.join(args.disable_checker)
result.extend(['-analyzer-disable-checker', checkers])
- if os.getenv('UBIVIZ'):
- result.append('-analyzer-viz-egraph-ubigraph')
return prefix_with('-Xclang', result)
push @Args, "-Xclang", $arg;
}
- # Display Ubiviz graph?
- if (defined $ENV{'CCC_UBI'}) {
- push @Args, "-Xclang", "-analyzer-viz-egraph-ubigraph";
- }
-
if (defined $AnalyzerTarget) {
push @Args, "-target", $AnalyzerTarget;
}
+++ /dev/null
-#!/usr/bin/env python
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===--------------------------------------------------------------------===##
-#
-# This script reads visualization data emitted by the static analyzer for
-# display in Ubigraph.
-#
-##===--------------------------------------------------------------------===##
-
-import xmlrpclib
-import sys
-
-
-def Error(message):
- print >> sys.stderr, 'ubiviz: ' + message
- sys.exit(1)
-
-
-def StreamData(filename):
- file = open(filename)
- for ln in file:
- yield eval(ln)
- file.close()
-
-
-def Display(G, data):
- action = data[0]
- if action == 'vertex':
- vertex = data[1]
- G.new_vertex_w_id(vertex)
- for attribute in data[2:]:
- G.set_vertex_attribute(vertex, attribute[0], attribute[1])
- elif action == 'edge':
- src = data[1]
- dst = data[2]
- edge = G.new_edge(src, dst)
- for attribute in data[3:]:
- G.set_edge_attribute(edge, attribute[0], attribute[1])
- elif action == "vertex_style":
- style_id = data[1]
- parent_id = data[2]
- G.new_vertex_style_w_id(style_id, parent_id)
- for attribute in data[3:]:
- G.set_vertex_style_attribute(style_id, attribute[0], attribute[1])
- elif action == "vertex_style_attribute":
- style_id = data[1]
- for attribute in data[2:]:
- G.set_vertex_style_attribute(style_id, attribute[0], attribute[1])
- elif action == "change_vertex_style":
- vertex_id = data[1]
- style_id = data[2]
- G.change_vertex_style(vertex_id, style_id)
-
-
-def main(args):
- if len(args) == 0:
- Error('no input files')
-
- server = xmlrpclib.Server('http://127.0.0.1:20738/RPC2')
- G = server.ubigraph
-
- for arg in args:
- G.clear()
- for x in StreamData(arg):
- Display(G, x)
-
- sys.exit(0)
-
-
-if __name__ == '__main__':
- main(sys.argv[1:])