C and C++ Binaries C# Java

Visitors

Visitors specify actions to be carried out on elements of the CodeSonar internal representation (IR) at various stages of the analysis.

Language Module Support: visitors can be applied to C/C++, C#, and Java analyses (including analyses that involve some combination of these). However, C# and Java analyses do not generate internal representation for points or symbols, so point visitors, step visitors, and symbol visitors will generally not produce useful information when applied to those analyses.



Overview

Visitors specify actions to be carried out on elements of the CodeSonar internal representation (IR) at various stages of the analysis.

Most visitors consist of a function and a list of languages, except for step visitors (which consist of a set of four functions and a list of languages). Visitors can be attached to any of a number of visitor lists, which determine when and to which IR element types the function will be applied. The list of languages in the visitor provides an additional level of control: the function will only be applied to IR elements whose language appears on the list.

Each visitor list is associated with an element type, a traversal phase, and a visit time.

element type Visitors can be applied to the following IR elements.
IR element visitor function type(s)
program () -> *
compilation unit compunit -> *
source file sfileinst -> * (applied only to representative instance)
source file instance sfileinst -> *
procedure (PDG) procedure -> *
point (PDG_VERTEX) point -> *
symbol (ABS_LOC) symbol -> *
CFG edge step visitor

For maximal efficiency, use the finest granularity visitor that is appropriate for your check. The finer the granularity, the more likely it is that the analysis structures will fit in memory: a visitor at procedure level or below will probably not incur any page faults at all.

All calls will be made from the same thread, so context information can be managed in the global scope if required.

traversal phase Each visitor list is associated with one of five phases.
  1. [Incremental Mode Only] The drop phase occurs before the setup phase and allows users to clean up any user-generated state that has been saved for program elements that are being dropped.
  2. The setup phase occurs before the remaining analysis traversals. Any new warning classes must be created in the setup phase, but warnings cannot be reported until the traversal phases.
  3. The serial depth-first phase groups procedures by compilation unit.
  4. The parallel depth-first phase groups procedures by compilation unit.

    (The pointer analysis phase occurs between the parallel depth-first phase and the bottom-up phase, but has no associated visitors.)

  5. The bottom-up phase sorts the procedures in reverse topological order of the call graph (leaf functions are visited first). Step visitors are applied during the bottom-up phase: they are applied after the point visitors and before the procedure finish visitors.
    Some program elements, such as symbols, do not have bottom-up visitors. Visitors for these element types must be added to the serial depth-first or parallel depth-first phase.
(Note that there are no visitors are associated with the pointer analysis phase.)
visit time For a specific element type and traversal phase, a visitor list may be associated either with beginning traversal of the element or with finishing traversal of the element. We describe these lists as containing "visitors" and "finish visitors", respectively.

Available Visitor Types

The following table shows the available visitor types.

IR element drop phase serial depth-first phase parallel depth-first phase bottom-up phase
visitor finish visitor visitor finish visitor visitor finish visitor
program* x x x x x x x
compilation unit x x x x x . .
source file . x x x x . .
source file instance . x x x x . .
procedure (PDG) x x x x x x x
point (PDG_VERTEX) . x . x . x .
symbol (ABS_LOC) x** x . x . . .
CFG edge (step visitors) . . . . . x .

Note that there are no finish visitors for source file instances, points (PDG_VERTEX) or variable symbols (ABS_LOC). This is because they are leaves of the traversal trees: no traversal takes place below them, so there is no distinction between starting and finishing.

Additional Notes

Program-level Visitors

Program-level visitors are not actually applied during the analysis traversals, but immediately before and after them.

Step Visitors

There are several differences between step visitors and the other kinds of visitor:

Step visitors have the following limitations.

Note: Step visitors will generally not produce useful information when applied to C# and Java analyses, because internal representation for points is not generated for those analyses .

Drop Visitors

When CodeSonar runs in incremental mode, drop visitors are applied during the drop phase to IR elements that existed in the previous analysis of the project but will not exist in the current analysis.

Use drop visitors to clean up any additional information that your plug-in has associated with these elements. Drop visitors are not responsible for cleaning up the elements themselves: CodeSonar will do that.

Because the IR elements no longer exist, drop visitors should not access their contents. The only API functions that can be called by drop visitors are:

C++ warning::retract(), procedure::operator==, procedure::hash(), compunit::operator==, compunit::hash(), symbol::operator==, symbol::hash()
Python warning.retract(), procedure.__eq__(), procedure.__hash__(), compunit.__eq__(), compunit.__hash__(), symbol.__eq__(), symbol.__hash__()
C csonar_retract_warning(), cs_pdg_equal(), cs_pdg_hash(), cs_uid_equal(), cs_uid_hash(), cs_abs_loc_equal(), cs_abs_loc_hash()

Visitors in Parallel Analyses

If the analysis runs in serial mode, all visitors are called by the analysis process. In parallel analyses, responsibility for applying visitors is divided between the analysis master and the analysis slaves as shown in the following table.

Analysis Phase Visitor Application
drop All visitors are called by the analysis master.
serial depth-first All visitors are called by the analysis master.
parallel depth-first Program parallel visitors and program parallel finish visitors are called by the analysis master.
Traversal for each compilation unit is handled by a single analysis slave, which calls all visitors applied during that traversal.
pointer analysis (no visitors in this phase)
bottom up The master manages a set of slaves during the bottom-up traversal, with each slave calling all the applicable visitors for a single procedure and the elements it contains. The master is responsible for calling program bottom-up visitors.

An example trace is provided below.

Visitors in Incremental Analyses

In incremental analyses, visitors are applied as follows.

Analysis Phase Visitor Application
drop Drop visitors are applied, as described above.
serial depth-first
  • Program visitors are always applied.
  • Compilation unit visitors are applied only to compilation units compiled in the increment.
  • File instance visitors are applied to file instances in compilation units compiled in the increment.
  • File visitors are applied only to files for which all remaining instances are in compilation units compiled in the increment.
  • Procedure (point, symbol) visitors are applied to all procedures (points, eligible symbols) contained in compilation units compiled in the increment.
parallel depth-first
  • Program parallel visitors are always applied.
  • Compilation unit parallel visitors are applied only to compilation units compiled in the increment.
  • File instance parallel visitors are applied to file instances in compilation units compiled in the increment.
  • File parallel visitors are applied only to files for which all remaining instances are in compilation units compiled in the increment.
  • Procedure (point, symbol) parallel visitors are applied to all procedures (points, eligible symbols) contained in compilation units compiled in the increment.
pointer analysis (no visitors in this phase)
bottom up
  • Program visitors are always applied.
  • For remaining visitors, CodeSonar identifies the set P, consisting of all procedures contained in files compiled in the increment plus all procedures whose summaries are needed during the incremental analysis but need to be recomputed because they rely on elements that were deleted or modified by the incremental changes. Then:
    • procedure visitors are applied to all procedures in P.
    • point visitors are applied to all points of all procedures in P.
    • Step visitors are applied to CFG edges in all procedures in P.

Example

Here is an example trace of calls that CodeSonar might make to the various visitors for a program with two compilation units, each including foo.h and defining two procedures, each with two points, two CFG edges, and two local symbols. All procedures have no arguments and return void. Assume pdg4 calls pdg1 which calls pdg3 which calls pdg2. The order in which visitors registered with the same function are called is undefined. Assume there is exactly one visitor of each kind.

In this example, the analysis is running in parallel mode (see Visitors in Parallel Analyses above for more information). For the sake of clarity we refer to slaves A, B, C and D in the trace that follows; note that:

CALLING  | VISITOR
PROCESS  |
---------+--------
master   |  setup_visitor
master   |   program_visitor
master   |     uid_visitor(uid1)
master   |         pdg_visitor(pdg1 in uid1)
master   |         abs_loc_visitor(function abs_loc alf1 corresponding to pdg1)
master   |             abs_loc_visitor(al1 referenced in pdg1)
master   |             abs_loc_visitor(al2 referenced in pdg1)
master   |             pdg_vertex_visitor(v1 in pdg1)
master   |             pdg_vertex_visitor(v2 in pdg1)
master   |         pdg_finish_visitor(pdg1 in uid1)
master   |         pdg_visitor(pdg2 in uid1)
master   |         abs_loc_visitor(function abs_loc alf2 corresponding to pdg2)
master   |             abs_loc_visitor(al3 referenced in pdg2)
master   |             abs_loc_visitor(al4 referenced in pdg2)
master   |             pdg_vertex_visitor(v3 in pdg2)
master   |             pdg_vertex_visitor(v4 in pdg2)
master   |         pdg_finish_visitor(pdg2 in uid1)
master   |         sf_visitor(sfid1 (=comp1.c) )
master   |             sfi_visitor(sfid1 (=comp1.c) )
master   |                 sf_visitor(sfid2 (=foo.h) )
master   |                     sfi_visitor(sfid2 (=foo.h) )
master   |                     sfi_finish_visitor(sfid2 (=foo.h) )
master   |                 sf_finish_visitor(sfid2 (=foo.h) )
master   |             sfi_finish_visitor(sfid1 (=comp1.c) )
master   |         sf_finish_visitor(sfid1 (=comp1.c) )
master   |     uid_finish_visitor(uid1)
master   |     uid_visitor(uid2)
master   |         pdg_visitor(pdg3 in uid2)
master   |         abs_loc_visitor(function abs_loc alf3 corresponding to pdg3)
master   |             abs_loc_visitor(al5 referenced in pdg3)
master   |             abs_loc_visitor(al6 referenced in pdg3)
master   |             pdg_vertex_visitor(v5 in pdg3)
master   |             pdg_vertex_visitor(v6 in pdg3)
master   |         pdg_finish_visitor(pdg3 in uid2)
master   |         pdg_visitor(pdg4 in uid2)
master   |         abs_loc_visitor(function abs_loc alf4 corresponding to pdg4)
master   |             abs_loc_visitor(al7 referenced in pdg4)
master   |             abs_loc_visitor(al8 referenced in pdg4)
master   |             pdg_vertex_visitor(v7 in pdg4)
master   |             pdg_vertex_visitor(v8 in pdg4)
master   |         pdg_finish_visitor(pdg4 in uid2)
master   |         sf_visitor(sfid3 (=comp2.c) )
master   |             sfi_visitor(sfid3 (=comp2.c) )
master   |                 sfi_visitor(sfid4 (=foo.h) )
master   |                 sfi_finish_visitor(sfid4 (=foo.h) )
master   |             sfi_finish_visitor(sfid3 (=comp2.c) )
master   |         sf_finish_visitor(sfid3 (=comp2.c) )
master   |     uid_finish_visitor(uid2)
master   |   program_finish_visitor
master   |   program_parallel_visitor
slave A  |     uid_parallel_visitor(uid1)
slave A  |         pdg_parallel_visitor(pdg1 in uid1)
slave A  |         abs_loc_parallel_visitor(function abs_loc alf1 corresponding to pdg1)
slave A  |             abs_loc_parallel_visitor(al1 referenced in pdg1)
slave A  |             abs_loc_parallel_visitor(al2 referenced in pdg1)
slave A  |             pdg_vertex_parallel_visitor(v1 in pdg1)
slave A  |             pdg_vertex_parallel_visitor(v2 in pdg1)
slave A  |         pdg_parallel_finish_visitor(pdg1 in uid1)
slave A  |         pdg_parallel_visitor(pdg2 in uid1)
slave A  |         abs_loc_parallel_visitor(function abs_loc alf2 corresponding to pdg2)
slave A  |             abs_loc_parallel_visitor(al3 referenced in pdg2)
slave A  |             abs_loc_parallel_visitor(al4 referenced in pdg2)
slave A  |             pdg_vertex_parallel_visitor(v3 in pdg2)
slave A  |             pdg_vertex_parallel_visitor(v4 in pdg2)
slave A  |         pdg_parallel_finish_visitor(pdg2 in uid1)
slave A  |         sf_parallel_visitor(sfid1 (=comp1.c) )
slave A  |             sfi_parallel_visitor(sfid1 (=comp1.c) )
slave A  |                 sf_parallel_visitor(sfid2 (=foo.h) )
slave A  |                     sfi_parallel_visitor(sfid2 (=foo.h) )
slave A  |                     sfi_parallel_finish_visitor(sfid2 (=foo.h) )
slave A  |                 sf_parallel_finish_visitor(sfid2 (=foo.h) )
slave A  |             sfi_parallel_finish_visitor(sfid1 (=comp1.c) )
slave A  |         sf_parallel_finish_visitor(sfid1 (=comp1.c) )
slave A  |     uid_parallel_finish_visitor(uid1)
slave B  |     uid_parallel_visitor(uid2)
slave B  |         pdg_parallel_visitor(pdg3 in uid2)
slave B  |         abs_loc_parallel_visitor(function abs_loc alf3 corresponding to pdg3)
slave B  |             abs_loc_parallel_visitor(al5 referenced in pdg3)
slave B  |             abs_loc_parallel_visitor(al6 referenced in pdg3)
slave B  |             pdg_vertex_parallel_visitor(v5 in pdg3)
slave B  |             pdg_vertex_parallel_visitor(v6 in pdg3)
slave B  |         pdg_parallel_finish_visitor(pdg3 in uid2)
slave B  |         pdg_parallel_visitor(pdg4 in uid2)
slave B  |         abs_loc_parallel_visitor(function abs_loc alf4 corresponding to pdg4)
slave B  |             abs_loc_parallel_visitor(al7 referenced in pdg4)
slave B  |             abs_loc_parallel_visitor(al8 referenced in pdg4)
slave B  |             pdg_vertex_parallel_visitor(v7 in pdg4)
slave B  |             pdg_vertex_parallel_visitor(v8 in pdg4)
slave B  |         pdg_parallel_finish_visitor(pdg4 in uid2)
slave B  |         sf_parallel_visitor(sfid3 (=comp2.c) )
slave B  |             sfi_parallel_visitor(sfid3 (=comp2.c) )
slave B  |                 sfi_parallel_visitor(sfid4 (=foo.h) )
slave B  |                 sfi_parallel_finish_visitor(sfid4 (=foo.h) )
slave B  |             sfi_parallel_finish_visitor(sfid3 (=comp2.c) )
slave B  |         sf_parallel_finish_visitor(sfid3 (=comp2.c) )
slave B  |     uid_parallel_finish_visitor(uid2)
master   |   program_parallel_finish_visitor
master   |   program_bottom_up_visitor
slave A  |     pdg_bottom_up_visitor(pdg2)
slave A  |        pdg_vertex_bottom_up_visitor(v3 in pdg2)
slave A  |        pdg_vertex_bottom_up_visitor(v4 in pdg2)
slave A  |        step_visitor(cfg edge e3 in pdg2)
slave A  |        step_visitor(cfg edge e4 in pdg2)
slave A  |     pdg_bottom_up_finish_visitor(pdg2)
slave B  |     pdg_bottom_up_visitor(pdg3)
slave B  |        pdg_vertex_bottom_up_visitor(v5 in pdg3)
slave B  |        pdg_vertex_bottom_up_visitor(v6 in pdg3)
slave B  |        step_visitor(cfg edge e5 in pdg3)
slave B  |        step_visitor(cfg edge e6 in pdg3)       
slave B  |     pdg_bottom_up_finish_visitor(pdg3)
slave C  |     pdg_bottom_up_visitor(pdg1)
slave C  |        pdg_vertex_bottom_up_visitor(v1 in pdg1)
slave C  |        pdg_vertex_bottom_up_visitor(v2 in pdg1)
slave C  |        step_visitor(cfg edge e1 in pdg1)
slave C  |        step_visitor(cfg edge e2 in pdg2)
slave C  |     pdg_bottom_up_finish_visitor(pdg1)
slave D  |     pdg_bottom_up_visitor(pdg4)
slave D  |        pdg_vertex_bottom_up_visitor(v7 in pdg4)
slave D  |        pdg_vertex_bottom_up_visitor(v8 in pdg4)
slave D  |        step_visitor(cfg edge e7 in pdg4)
slave D  |        step_visitor(cfg edge e8 in pdg4)
slave D  |     pdg_bottom_up_finish_visitor(pdg4)
master   |   program_bottom_up_finish_visitor

Defining and Adding Visitors

Visitors other than step visitors are added by defining a visitor function and then instructing CodeSonar to add it as a particular kind of visitor. Step visitors involve a slightly different mechanism.

In both cases, the adding operation must take place in a specific location.

API language Visitors must be added...
C++ ...in the top-level scope of the plug-in, or in cs_plug_main().
Python ...in the top-level scope of the plug-in.
C ...in cs_plug_main().

Adding: All visitor types except step visitors

There are two stages involved in adding a visitor.

  1. Implement the function that will carry out the work of the visitor.
  2. Instruct CodeSonar to add the function to the appropriate visitor list.
API language Add a visitor with Main work of visitor carried out by
C++ analysis::add_*_visitor()(vobj, langs)
where vobj points to an instance of a concrete subclass VSC of class visitor with member data suitably initialized.
vobj->operator()
Python Applying the appropriate visitor decorator to visitor function vf(). vf()
C csonar_add_*_visitor(langs, vf, ctx)
Where vf points to the visitor function.
vf()

Adding: Step visitors

There are three stages involved in adding a step visitor.

  1. Identify the state information that the visitor will need to track (this will be the USER_STATE described above).
    API language USER_STATE corresponds to
    C++ an instance of a concrete cs::step_state subclass
    Python an instance of a concrete cs.step_state subclass
    C data of type cs_step_user_state_t (treated as opaque by CodeSonar)
  2. Implement the step visitor operations open (where required), copy, transition, close with respect to USER_STATE and the goals of the step visitor.
  3. Instruct CodeSonar to add the step visitor.
API language Add a step visitor with... Step Visitor Operations
open copy transition close
C++ analysis::add_step_bottom_up_visitor(ssobj, langs)
where ssobj points to an instance of a concrete subclass SSSC of class step_state with member data suitably initialized.
ssobj->copy() SSSC::copy() SSSC::transition() SSSC destructor
Python analysis.add_step_bottom_up_visitor(ssobj, langs)
where ssobj is an instance of a concrete subclass SSSC of class step_state with member data suitably initialized.
ssobj.copy() SSSC.copy() SSSC.transition() SSSC destructor
C csonar_add_step_bottom_up_visitor( langs, svis, ctx )
where svis points to a cs_step_visitor_dispatch_t
svis->open() svis->copy() svis->transition() svis->close()

Visitor-Adding Functionality, by Phase.

The following table shows the API functions for adding visitors at the various build/analysis phases.

Build/Analysis Phase API Language
C++ Python C
drop phase analysis::add_project_drop_visitor()
analysis::add_compunit_drop_visitor()
analysis::add_procedure_drop_visitor()
analysis::add_global_symbol_drop_visitor()
analysis::add_project_drop_finish_visitor()
@project_drop_visitor
@compunit_drop_visitor
@procedure_drop_visitor
@global_symbol_drop_visitor
@project_drop_finish_visitor
csonar_add_program_drop_visitor()
csonar_add_uid_drop_visitor()
csonar_add_pdg_drop_visitor()
csonar_add_global_abs_loc_drop_visitor()
csonar_add_program_drop_finish_visitor()
after drop traversal, before anything else (do setup work in top level scope) (do setup work in top level scope) csonar_add_setup_visitor()
serial depth-first analysis phase analysis::add_project_visitor()
analysis::add_compunit_visitor()
analysis::add_sfile_visitor()
analysis::add_sfileinst_visitor()
analysis::add_sfileinst_finish_visitor()
analysis::add_sfile_finish_visitor()
analysis::add_procedure_visitor()
analysis::add_point_visitor()
analysis::add_symbol_visitor()
analysis::add_procedure_finish_visitor()
analysis::add_compunit_finish_visitor()
analysis::add_project_finish_visitor()
@project_visitor
@compunit_visitor

@sfile_visitor
@sfileinst_visitor
@sfileinst_finish_visitor
@sfile_finish_visitor
@procedure_visitor
@point_visitor
@symbol_visitor
@procedure_finish_visitor
@compunit_finish_visitor
@project_finish_visitor
csonar_add_program_visitor()
csonar_add_uid_visitor()
csonar_add_sf_visitor()
csonar_add_sfi_visitor()
csonar_add_sfi_finish_visitor()
csonar_add_sf_finish_visitor()
csonar_add_pdg_visitor()
csonar_add_pdg_vertex_visitor()
csonar_add_abs_loc_visitor()
csonar_add_pdg_finish_visitor()
csonar_add_uid_finish_visitor()
csonar_add_program_finish_visitor()
parallel depth-first analysis phase analysis::add_project_parallel_visitor()
analysis::add_compunit_parallel_visitor()
analysis::add_sfile_parallel_visitor()
analysis::add_sfileinst_parallel_visitor()
analysis::add_sfileinst_parallel_finish_visitor()
analysis::add_sfile_parallel_finish_visitor()
analysis::add_procedure_parallel_visitor()
analysis::add_point_parallel_visitor()
analysis::add_symbol_parallel_visitor()
analysis::add_procedure_parallel_finish_visitor()
analysis::add_compunit_parallel_finish_visitor()
analysis::add_project_parallel_finish_visitor()
@project_parallel_visitor
@compunit_parallel_visitor
@sfile_parallel_visitor
@sfileinst_parallel_visitor
@sfileinst_parallel_finish_visitor
@sfile_parallel_finish_visitor
@procedure_parallel_visitor
@point_parallel_visitor
@symbol_parallel_visitor
@procedure_parallel_finish_visitor
@compunit_parallel_finish_visitor
@project_parallel_finish_visitor
csonar_add_program_parallel_visitor()
csonar_add_uid_parallel_visitor()
csonar_add_sf_parallel_visitor()
csonar_add_sfi_parallel_visitor()
csonar_add_sfi_parallel_finish_visitor()
csonar_add_sf_parallel_finish_visitor()
csonar_add_pdg_parallel_visitor()
csonar_add_pdg_vertex_parallel_visitor()
csonar_add_abs_loc_parallel_visitor()
csonar_add_pdg_parallel_finish_visitor()
csonar_add_uid_parallel_finish_visitor()
csonar_add_program_parallel_finish_visitor()
bottom-up analysis phase analysis::add_project_bottom_up_visitor()
analysis::add_procedure_bottom_up_visitor()
analysis::add_point_bottom_up_visitor()
analysis::add_step_bottom_up_visitor()
analysis::add_procedure_bottom_up_finish_visitor()
analysis::add_project_bottom_up_finish_visitor()
@project_bottom_up_visitor
@procedure_bottom_up_visitor
@point_bottom_up_visitor
analysis.add_step_bottom_up_visitor()
@procedure_bottom_up_finish_visitor
@project_bottom_up_finish_visitor
csonar_add_program_bottom_up_visitor()
csonar_add_pdg_bottom_up_visitor()
csonar_add_pdg_vertex_bottom_up_visitor()
csonar_add_step_bottom_up_visitor()

csonar_add_pdg_bottom_up_finish_visitor()
csonar_add_program_bottom_up_finish_visitor()
(periodically, as analysis progresses) analysis::add_cache_cleanup_visitor() @cache_cleanup_visitor csonar_add_cache_cleanup_visitor()

More on Plug-Ins

General Information:

Visitors
(this page)
Plug-ins are based on visitors, which specify actions to be carried out on elements of the CodeSonar internal representation (IR) at various stages of the analysis.
Writing Plug-Ins General information about creating plug-ins to attach custom functionality to the CodeSonar analysis.
Custom Checks: Accounting for Incrementality Ensuring that custom checks implemented in plug-ins generate appropriate results in incremental analyses.
Plug-In Tutorial Two annotated example plug-ins (each provided in all API languages), with building and installation instructions.
AST API Tutorial The AST API tutorial (provided in all API languages) also uses plug-ins.

Specific API Language:

  Plug-In Guidelines Key API References
C++ Writing C++ Plug-Ins classes analysis, visitor, warningclass, project_metricclass, compunit_metricclass, sfile_metricclass, procedure_metricclass.
Python Writing Python Plug-Ins Visitor decorators, Metric decorators; classes analysis, warningclass, project_metricclass, compunit_metricclass, sfile_metricclass, procedure_metricclass.
C Writing C Plug-Ins CodeSonar Plug-In API: C Functions and Types for Visitors, Warnings, and Metrics