JavaScript is not currently enabled, but is required for full CodeSonar manual search and browse functionality.

If you are viewing this file in your hub's Web GUI, enable JavaScript in your browser: you will also need it for GUI functionality.

If you opened this file directly from disk, your browser may be directly suppressing JavaScript functionality: certain browsers perform this suppression on local files (but not files delivered by web servers) for security reasons.

CodeSonar® 9.2p0 CONFIDENTIAL CodeSecure Inc
C and C++
Binaries

Custom Checks: Accounting for Incrementality

CodeSonar plug-ins that implement custom warning classes must account for incremental analyses, otherwise they may encounter accidental false positives, false negatives, and duplicate warnings. There are two important elements:



Overview

If you haven't already read the manual page on incrementality it may be useful to do so before proceeding: it provides context for the material on this page.

When you implement a custom warning class, an important goal is for all of the following to be true after an incremental analysis.

To satisfy this goal, the warning class plug-in must do two things.

The remainder of this page discusses the decisions and requirements involved in implementing a custom check that behaves as desired in incremental analyses. While it is generally most straightforward to consider these issues when initially designing the check, the same principles can be applied to modify existing plug-ins. The page is organized as follows.

Determining Retraction Conditions

When you are designing a check for a custom warning class, think about which incremental program changes should cause a warning of this class to be retracted. There are three important factors to bear in mind.

Selecting a Retraction Strategy

Once you have determined the conditions under which a warning should be retracted, work through the following checklist to determine how to proceed.

  1. Is this a "global warning" (that is, one that applies to the analysis as a whole rather than to a specific file, procedure, or other program location)?
  2. Check the default automated retraction behavior for the warning reporting function you are using. Is this behavior suitable for your warnings?
  3. If the default automated retraction behavior isn't appropriate, determine whether you can fully describe the required retraction behavior with a retraction info value.
  4. If neither form of automated retraction behavior is suitable for your retraction conditions, your plug-in will need to manually retract warnings.

Note: If warnings of your custom class are issued under complicated conditions, the considerations involved in implementing suitable retraction behavior may lead to new insights about the analysis phase behavior required of your checker. See below for an example.

Default Automated Retraction

The CodeSonar API provides a wide range of warning reporting functionality covering the various kinds of structural information that might be associated with a warning. For example:

In the C++ and Python APIs, this functionality range is provided by overloading the warning class report() and report_return_warning() methods. In the C API, it is provided by a set of functions with names of the form csonar_report*_warning(). For more information, see Writing and Debugging CodeSonar Plug-Ins: Issuing Warnings.

Each warning reporting function (or overload) has a default retraction behavior, and provides a mechanism for specifying that this default should be applied. The default behavior depends on the individual function or overload: consult the function documentation for details. There is one exception: warnings associated with the analysis as a whole ("global warnings") are always retracted in incremental analyses.

For example, consider the functions that report a warning at a single program point P. The default warning retraction behavior for a warning issued with one of these functions is to retract it if and only if the procedure containing P is modified between incremental analyses. This is often going to be exactly what you want, because if the warning were affected by parts of the program beyond the immediately-containing procedure you would probably be using a different reporting function: one that allows you to describe all the relevant program locations.

C++ warningclass::report(point, const std::string &[, report_flags[, const warning_retraction_info &]])
or
warningclass::report_return_warning(point, const std::string &[, report_flags[, const warning_retraction_info) &]])
Python warningclass.report(point, str[, report_flags[, warning_retraction_info]])
or
warningclass.report_return_warning(point, str[, report_flags[, warning_retraction_info]])
C csonar_report_warning()

Using Default Automated Retraction

If the default behavior for the function you are using is appropriate for your check, you don't need to construct explicit retraction conditions when you report a warning. Instead, use the appropriate mechanism for specifying that the default retraction behavior should be applied.

Customized Automated Retraction

All implementations of the CodeSonar API provide a retraction info data type, such that a value of this type characterizes the conditions for automatically retracting a single warning instance.

C++ warning_retraction_info
Python warning_retraction_info
C cs_warning_retraction_info_t

Considered abstractly, retraction info always consists of three sets bu_procs, changed_procs, changed_compunits, such that CodeSonar will automatically retract the corresponding warning instance in an incremental analysis A (with parent analysis Aparent) if any of the following are true.

To determine which of bu_procs and changed_procs is the appropriate set to use in specifying relevant procedures for retraction, the most important factor will be the kind of visitor that issues the warning.

Before opting to use customized automated retraction, make sure that it cannot lead to false negatives for your check. These can arise if your specified retraction info values cause a warning to be retracted but, due to the incremental nature of the analysis, the warning is not subsequently reissued even though its conditions are met. (For more details, see Accounting for Incrementality when Reporting Warnings, below.) If you can't coordinate the conditions for automated retraction and those for reissuing the warning if it's still present, use manual retraction instead.

Using Customized Automated Retraction

In order to take advantage of customized automated retraction, your plug-in must do the following.

Manual Retraction

If neither default automated retraction nor customized automated retraction is sufficient to express the circumstances under which a warning of your custom class should be retracted, you will need to define a drop phase visitor that checks the necessary retraction conditions for each warning of that class that is present in the parent analysis, explicitly retracting those for which the conditions are met.

This mechanism has two important consequences.

Storing Retraction Information

Any plug-in that performs explicit warning retraction will need to store information about each warning that may be retracted.

This information must be stored using some mechanism that persists between analyses. In most cases, it will be sufficient to use a dedicated file, as follows.

The following API functionality is useful for storing warning information between analyses.

API Implementation Identify reported warnings Serialize/Deserialize warnings
C++ Report with warningclass::report_return_warning()
(not warningclass::report())
warning::serialize()
warning::warning()
Python Report with warningclass.report_return_warning()
(not warningclass.report())
warning.serialize()
warning.__init__()
C Warning reporting functions output the cs_warning_id of the reported function as an out parameter. Store/retrieve the cs_warning_id that was output by the warning reporting function.

Performing Manual Retraction

To set up your plug-in to perform manual retraction, do the following.

  1. Ensure that the plug-in obtains and stores all necessary information every time it reports a warning.
  2. Add a drop visitor to the plug-in and implement the retraction logic. This will involve three phases, as follows.
    1. Retrieve the information that the plug-in stored for the parent analysis.
    2. For each warning with information recorded, check whether the conditions for retraction are satisfied.
      Note that the subset of API functions available in drop visitors is severely restricted.
    3. For each warning W to be retracted, call the warning retraction function.
      C++ W.retract()
      Python W.retract()
      C csonar_retract_warning(W)

Accounting for Incrementality when Reporting Warnings

As discussed above, determining retraction behavior for your custom warning class will always involve considering your warning reporting conditions and operations, and will sometimes also involve extending the part of your plug-in that reports warnings. At minimum, implementing a retraction strategy will involve the following.

Default automated retraction Investigate the default retraction behavior for the warning reporting function you are using and confirmed that it is appropriate for your check.
Customized automated retraction Compute and pass a suitable retraction info value for every warning reported.
Manual retraction Store sufficient information about every warning reported (minimally, the warning itself).

If warnings of your custom class are issued under complicated conditions, the considerations involved in implementing suitable retraction behavior may also lead to new insights about the analysis phase behavior required of your checker.

For example, suppose we have implemented a customer checker prototype using a procedure visitor. Each warning is issued in a particular procedure, under conditions that depend on one or more additional procedures that are not necessarily in the same compilation unit.

Imagine a project with procedures procX and procY in compilation units compunitA and compunitB, respectively, such that:

diagram: visitor visits both procX and procY, issuing a warning in the latter only

Because this warning depends on both procX and procY, we determine that it should be retracted if either of these procedures changes. This condition can be expressed in a warning retraction info data object, so we can take advantage of customized automated retraction.

However, we also consider the conditions under which the plug-in will be able to reissue warningW in an incremental analysis.

In considering retraction and reanalysis behavior, we have identified a problem with using a procedure visitor to implement the check: it can lead to false negatives.

It remains to determine how the check should be adjusted: in particular, what kind of visitor it will need to use. In many complicated cases, the best option is to apply the check through a program visitor. These are the only visitors that are guaranteed to always be applied in an incremental analysis, independent of exactly which parts of the program were modified. The general approach is as follows.

  1. Add a program visitor to the plug-in.
  2. Add code to the program visitor so that it checks the analysis mode and applies your custom check to every element of the relevant type (for example, every procedure) if it is a base analysis or nonincremental analysis:
    C++ analysis::get_mode returns analysis_mode::NORMAL
    Python analysis.get_mode returns analysis_mode.NORMAL
    C csonar_get_analysis_mode() returns csam_normal
  3. Determine which elements of the relevant type (for example, procedures) your program visitor will need to check in incremental analyses.
    Will it be possible for the visitor to identify the relevant subset of elements for incremental checking?
relevant subset only In some cases the conditions for a check are such that only a characterizable subset of elements must be checked in an incremental analysis. For example, if a warning depends on properties of a procedure and its callees, then—depending on the precise properties involved—it may be appropriate to restrict incremental checking only to procedures that are new or modified or whose callees have been modified.

If your check falls into this category it is generally best to take advantage of it. While it is possible to re-check the entire program, this will typically involve a higher resource cost.

You can overapproximate the set of new and modified procedures by taking advantage of a useful property of procedure unique identifiers: a procedure in an incremental analysis will have the same identifier that it did in the incremental parent if and only if the containing compilation unit is not recompiled. If the containing compilation unit is recompiled, the procedure will have a new unique identifier not previously used for any procedure in any incremental ancestor analysis.

  1. For each analysis, make a persistent record of all procedure identifiers in the project (use a project visitor or project finish visitor). For example, save them to a file.
    C++ project::procedures(), procedure::id()
    Python project.procedures(), procedure.get_id()
    C cs_sdg_pdgs(), cs_pdg_procedure_id()
  2. Overapproximate the set of new and modified procedures in an incremental analysis as follows.
    1. Retrieve the set of procedure identifiers that your plug-in recorded for the parent analysis. (For example, load a previously-saved file.)
    2. For each procedure in the incremental analysis, check to see if it is present in the set.
      • YES: The procedure may be new or modified.
      • NO: The procedure is definitely not new or modified.
entire program If the warning conditions are such that a smaller set of candidate elements for incremental checking cannot be identified without checking the warning conditions for each element, the most suitable approach is to always check the entire program regardless of whether or not the current analysis is incremental. There are two general cases:
  • The warning conditions are fundamentally based on whole-program properties (such as a warning class for reporting cases where a program symbol has a name that is a prefix of another symbol's name has a condition that is based on the program's symbol set).
  • The warning conditions are based on complicated relationships between program elements.

Re-checking the entire program has two important consequences.

  • Every warning must be retracted in the drop phase (otherwise there will be duplication for every reissued warning).
    This must be accomplished through manual retraction, unless the warnings are reported by a global reporting function (in which case they are always retracted).
  • The analysis phase will generally take longer. The time involved will depend on the complexity of the check and the size of the program and may or may not represent a significant increase in overall analysis time.

More on Plug-Ins

General Information:

Visitors 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
(this page)
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
 

To report problems with this documentation, please visit https://support.codesecure.com/.