Svace 3.2.0 user guide

Svace is an automatic defect detection tool for source code written in C, C++, Java, Go, Kotlin and C# languages. The detection algorithms are based on static analysis. This software is copyrighted by Ivannikov Institute for System Programming of the Russian Academy of Sciences (ISP RAS).

Svace is a continuously evolving product based on long term research. It uses a number of unique state-of-the-art analysis technologies and adopts the front-end of several open compilers to support the latest language standards. Svace provides ease of integration with any build systems and allows to accurately capture the exact code being built and the details of its compilation. Svace analysis engine covers all program execution paths and considers function calls in particular. The analysis is fully parallel and scalable up to projects with tens of millions lines of code. Several third-party analyzers are integrated into Svace to widen the scope of detected issues. Analysis results are represented through detailed reports, where the traces provided for each reported issue support code navigation.

Outline

This User Guide includes the following main sections:

Introduction

Typically, analyzing source code with Svace involves four stages:

  • Compiling source code into intermediate representation files
  • Performing analysis of the code
  • Exporting the analysis results to a remote analysis history server or importing them to the local analysis history storage
  • Managing the history of previous analysis runs and evaluation status of previously detected issues (history storage)

Svace includes internal compilers to generate intermediate representation for analysis. For C/C++ Svace uses a modified version of Clang to produce the LLVM intermediate representation (bitcode) files. For Java, javac compiler from OpenJDK is used to produce bytecode. For C#, Roslyn is used.

The analysis tool uses the intermediate files and other data (including source code) produced and stored at the build phase to generate analysis result files (in various formats including plain text, XML and JSON).

History of previous analysis runs allows to indicate (for a new run) which issues were new to this run and which issues detected on this run were previously marked as incorrectly detected (false positives).

Dependencies and installation

Svace is released in 2 separate distributions:

  • Linux (x86_64, tested on Ubuntu from Trusty to Bionic)
  • Windows (x86_64, the minimum supported version is Windows 7 SP1 with update KB2533623)

The analyzer has no external dependencies and may be used right after unpacking.

Using Svace

This section describes how to perform analysis through command line interface, explaining the process of analysis in detail.

Initializing project folder

Svace stores all the data related to a project being analyzed in a special project folder. This folder can be created using a svace init tool.

Building source code

Svace provides the svace build tool to wrap a normal building command. This tool intercepts invocations of compilers supported by Svace (C/C++: GCC, ARMCC, Clang, icc, MSVC and multiple others; Java: OpenJDK, Oracle JDK and ECJ (including their usage via API)) and transparently runs Svace internal compilers along with the original compiler command.

Building in Tizen and Samsung Build System

Running the build command

For SBS make sure that 'sbs' is in PATH. The following command should now work from a source package directory:

svace build sbs -b

Similar procedure is for building a Tizen package using GBS. For example, to build a 'libxml2' package:

svace build gbs build -A armv7l --binary-list libxml2

Performing analysis

Use svace analyze command line tool.

Secondary analysis engines

A Svace distribution can additionally include Clang Static Analyzer and SpotBugs. Also, several lightweight defect detectors are implemented in Svace javac compiler. By default, all those tools are run before the main analysis, using intermediate data produced during the build phase as input. Defect reports produced by those tools are included into the final analysis results.

Performance tuning

Svace supports configuration options that may affect the analysis time. Default options should be suitable for most scenarios but it is possible to tune several parameters manually. By using the config tool it is possible to change them:

svace config THREAD_NUMBER 4

In the example above the THREAD_NUMBER configuration variable sets the number of parallel threads used for analysis as 4. By default the THREAD_NUMBER option has value 'auto' and the analyzer selects threads number depending of current processor loading. Value 'max' sets threads number equal to the processor kernels. And you may use any positive integer number. Usually analysis is faster if THREAD_NUMBER is 'max'. But every thread spend some amount of memory and more threads will spend more memory. So on machines with low memory it is better to reduce threads number.

Working with history storage

When the svace history tool is used after an analysis, analysis results are added to history storage. History storage for a project is located in its Svace directory. A history storage contains the list of known warnings found in the project, and snapshots of the relevant source code.

History storage allows to recognize some of the issues detected on a new analysis run as instances of previously detected issues (even if the source code and line numbers changed between the analyses). If an issue was marked as a 'false positive' after some analysis run, it will remain marked so in new analysis results.

Viewing the results

Analysis results may be viewed through a web-browser using a builtin server (see svace server) or a standalone Svacer history server, or opened with an editor.

Each issue detected by Svace is associated with the following information:

  • Warning type
  • Source location, warning message, warning trace
  • Evaluation status (Not inspected, True, Technically true, False or Unknown)

The analysis results are presented as a tree. The top level lists warnings by type, the second level lists the warnings themselves.

Each warning record shows location in the source code and warning message that may include names of the relevant expressions. For each warning, subnodes in the tree may indicate multiple source locations playing different roles in the warning (for example, for DEREF_AFTER_NULL, one location shows where the pointer is dereferenced, and the other location shows where it was compared to NULL). Together they form a warning trace that usually helps to understand the program flow from the defect occurrence to its manifestation point, or other useful information related to the warning.

When using a web-server warning status can be set by selecting appropriate value from the drop-down list, and is indicated by the color of the issue. There are the following options:

  • Not inspected - A default state for issues that weren't inspected yet
  • True - A correctly detected issue, that offers useful guidance about what should be changed in the source code
  • Technically true - A correctly detected issue, that should probably be left unchanged in the source code for some reason (e.g. given the assumptions specific to the analyzed source code, the detected issue isn't expected to cause problems)
  • False - An incorrectly detected issue
  • Unknown - An issue that was inspected, but it was too difficult to understand whether it's a correctly detected issue

Command line tools

The command line tools can be accessed through a wrapper tool 'svace' located in svace/bin/ (it's recommended to add this folder to PATH, so that 'svace' becomes accessible as a command). Command line options for 'svace' are as follows:

usage: svace <command> [args]
       svace --version [--quiet | --verbose]
       svace [--help]

This is the command-line interface for Svace static analysis tool.
Type 'svace help <command>' to get help on a specific command.

optional arguments:
  --help                Show this help message and exit.
  --version             Show version information and exit. If used together
                        with '--quiet', only version number in X.Y.Z format is
                        printed. If used together with '--verbose', source
                        code revision is printed too.
  --verbose             Increase output verbosity.
  --quiet               Reduce output verbosity.

commands:
  main:
    analyze             Run Svace static analyzer to search for defects in
                        source code, given the data gathered during 'svace
                        build'.
    build               Capture invocations of supported compilers performed
                        by a given command and generate intermediate data for
                        a subsequent analysis.
    config              Manage general configuration settings.
    init                Create a Svace project directory.
    warning             Control which warning types are enabled during
                        analysis.
  
  experimental:
    add                 Add new sources to current build.
    admin               Manage object pool in a project directory.
    clean               Remove old annotations.
    del                 Delete given sources from project.
    export-build        Export a build object into an external directory.
    fa-diff             Compare warning results for fast analysis mode for
                        oldand new svace distributives.
    history             Interact with a warning database.
    merge-build         Merge multiple build objects into a single build
                        object.
    nhistory            Interact with a new warning database.
    server              Configure or run Svace server.
    show                Show results in a Svace server (localhost:8060).
    spec                Manage user-provided specifications for third-party
                        library functions.
  
  miscellaneous:
    cgoc                Tool to compare call graph logs.
    cgop                Tool to calculate sub-call graph order.
    compare-details     Compare details for 2 svres files.
    compare-svres       Compare warnings from two .svres files ignoring
                        checker names and generate comparison stats.
    convert-svres       Convert analysis results files into newer or older
                        format versions.
    csa-stat            Display Clang Static Analyzer checker statistics
                        summary.
    diff-svres          Show diff for 2 svres files.
    filter-svres        Extract the issues enabled in given warning settings
                        file from a given .svres.
    ignore-test         Check svace.ignore filter.
    import-sqlite       Convert svace sqlite format db to svres.
    mark-multi-lang-warn
                        A tool marking multi-language warnings in svres
    match-svres         Match two svres files and show identifiers of the
                        matched warnings from the first svres file.
    merge-svres         Merge multiple .svres files with analysis results for
                        different projects into a single file.
    mti                 Calculate message template id from warning messages
                        taken from svres files.
    mti-csharp          Calculate message template id from warning messages
                        taken from svres files.
    quality-report      Print report about warnings quality for reviewed svres
                        files(s).
    review-rebase       Rebase warning review from one svres file to other.
    split-svres         Split a multi-project .svres file into separate files
                        with analysis results for individual projects.
    suppress            Run stand-alone suppression tool.
    svres2json          Converter from Svace results format to JSON format and
                        vice versa.
    warning-selector    Pick particular warnings and write them to an svres
                        file.

svace init

usage: svace init [options] [DIR]

Create an empty Svace project directory or reinitialize an existing one. By
default, this command creates a '.svace-dir' subdirectory in DIR (but see
--bare). If DIR is not specified, the value of SVACE_DIR environment variable
(or, if unset, the current directory) is used instead. If the project
directory already exists, this command can reinitialize its permissions
according to the options without changing the stored data. Note that only
permissions of the directory itself can be changed. Permissions of
subdirectories should be changed manually if desired.

optional arguments:
  --bare       Initialize the specified directory as a Svace project directory
               instead of creating '.svace-dir' subdirectory in it.
  --shared     (Linux only). Make the project directory group-writable and set
               the set-group-id bit on it. This allows users belonging to the
               current user's primary group to share this project directory.
  -q, --quiet  Print only error messages (to stderr).
  --help       Show this help message and exit.

svace build

This tool launches a specified custom build command, intercepts invocations of supported compilers and uses Svace internal compilers to produce intermediate representation of the same source code that is being built by the given command.

Command line options are as follows:

usage: svace build [options] <build-command>
       svace build [options] --update [TARGET...]

Run <build-command> and capture all invocations of supported compilers during
its execution. Create intermediate representation files using information from
the intercepted compiler invocations.

<build-command> can include options and arguments. To capture multiple
commands, wrap the commands in a single script.

Typical usage:
 svace build make -j4 all
 svace build --disable-language cxx gradle build

positional arguments:
  build-command

optional arguments:
  -h, --help            show this help message and exit
  --svace-dir SVACE_DIR
                        Specify a Svace directory, overriding current
                        directory and SVACE_DIR environment variable.
  --clear-build-dir     Remove redundant contents of the build directory after
                        build.
  --enable-language LANG, --disable-language LANG
                        Enable or disable compilation interception for the
                        specified programming language. Valid values are: all,
                        cxx, go, java, kotlin. By default, all languages are
                        enabled.
  --enable-dxr, --disable-dxr
                        Build source reference index used for source code
                        navigation (via history API). Note that it's also used
                        for filtering analysis results, so disabling it may
                        result in incorrect issues detected by analysis. By
                        default, it is enabled.
  --enable-csa, --disable-csa
                        Run Svace checkers implemented in Clang Static
                        Analyzer during the build phase. By default, this
                        feature is disabled.
  --enable-csa-deps, --disable-csa-deps
                        Prepare everything needed for running Clang Static
                        Analyzer during the analysis phase. By default, this
                        feature is enabled.
  --enable-tags-javac-checkers, --disable-tags-javac-checkers
                        Run Svace checkers implemented in tags-javac during
                        the build phase. By default, this feature is disabled.
  --enable-kotlinc-checkers, --disable-kotlinc-checkers
                        Run Svace checkers implemented in Kotlin compiler
                        during the build phase. By default, this feature is
                        disabled.
  --enable-spotbugs, --disable-spotbugs
                        Run SpotBugs checkers for intercepted Java
                        compilations during the build phase. By default, this
                        feature is disabled.
  --disable-java-agent  Don't inject Java agent into intercepted JVM
                        processes. If this option is used, Java compilations
                        performed via compiler APIs (e.g., javac API) are not
                        intercepted. Since Svace Java agent requires Java 1.6,
                        this option must be used if build process involves
                        Java 1.5 or older.
  --enable-ecj-interception, --disable-ecj-interception
                        Enable or disable interception of Java compilations
                        performed using Eclipse Compiler for Java (both via
                        command-line tool and via API). By default, it is
                        disabled.
  --enable-link-fixup, --disable-link-fixup
                        Attempt to fix missing links in source markup data by
                        heuristically linking similar symbols. This feature is
                        enabled by default.
  --enable-rebuild      Save information about how to rebuild the compiled
                        sources for the '--update' mode.
  --update              Rebuild a subset of source files built on the last
                        full build without invoking and intercepting a build
                        command. The full build must be performed with
                        --enable-rebuild to use this option. Targets are given
                        as canonical paths to the source files to be rebuilt
                        or special keywords: 'force' to rebuild all files, or
                        'incremental' to rebuild files changed since the
                        previous update if it was an incremental one or all
                        files otherwise. If no arguments are given, the
                        incremental mode is used.
  --merge               Merge result of this build with the previous build.
                        This way, a subsequent analysis will use all files
                        from the merged build object (not just those that were
                        rebuilt in the last build). Valid only in conjunction
                        with --update option. Not compatible with --update
                        force.
  --hash-server-memory HASH_SERVER_MEMORY
                        Specify maximum size of Java heap (in MB) that Svace
                        hash server may use (default: 2048).
  --spotbugs-memory SPOTBUGS_MEMORY
                        Specify maximum size of Java heap (in MB) that
                        SpotBugs may use (default: 2048).
  --tags-javac-memory TAGS_JAVAC_MEMORY
                        Specify maximum size of Java heap (in MB) that tags-
                        javac may use (default: 2048).
  --max-jobs MAX_JOBS   The maximum number of processes that Svace can use to
                        handle intercepted compilation commands. For full
                        builds, it is supported only on Windows. If combined
                        with --update, it is supported on all platforms. The
                        default value is the number of logical processors on
                        the system.
  --captured-nothing-status STATUS
                        If the build command completed successfully and no
                        serious Svace failures were detected, but no
                        compilations were successfully captured, exit with the
                        specified status (255 by default).
  --verbose             Report more detailed statistics after build.

experimental options:
  -t TARGET, --target TARGET
                        Specify the target platform that Clang should use for
                        bitcode generation. Valid values are: auto, aarch64,
                        arm, hexagon, mips, mips64, powerpc, powerpc64,
                        riscv32, riscv64, sparc, sparc64, x64, x86. Values
                        other than 'auto' override automatic target detection.
                        This option is intended for debugging only.
  --disable-bitcode-gen
                        Don't run Clang to generate bitcode files. Note that
                        disabling bitcode generation makes it impossible to
                        run Svace checkers on the resulting build object. It
                        is useful if you only want to get results from tools
                        run at the build time (e.g., warnings from CSA or
                        metrics). Turning on this option disables default
                        C/C++ metrics generation.
  --disable-pch-gen     Don't create an internal precompiled header (PCH) when
                        creation of a PCH by a supported compiler is detected.
                        Internal PCHs are used by Svace to speed up bitcode
                        generation for subsequent compilations, but might lead
                        to incorrect bitcode in some corner cases. In
                        particular, if an intercepted compiler creates a PCH
                        but rejects it in subsequent compilations (for
                        example, due to macro or option mismatch), falling
                        back to usage of normal headers, Svace might still use
                        an unsuitable internal PCH due to different mismatch
                        detection rules in Clang. PCH generation is currently
                        supported only for Clang and (partially) GCC.
  --enable-dxr-collect  (Linux only). Run a helper process that aims to reduce
                        load on the filesystem when building source reference
                        index is enabled (see --enable-dxr).
  --enable-ptrace       (Linux only). Use ptrace-based interception for
                        statically-linked executables.
  --enable-ptrace-all   (Linux only). Use ptrace-based interception for all
                        executables.
  --prepend-preload-lib
                        (Linux only). By default, the Svace library for
                        function call interception is appended to LD_PRELOAD
                        environment variable, ensuring that necessary
                        environment variables are propagated across the
                        process tree even if other LD_PRELOAD-libraries are
                        used in the course of the build process. However, if
                        such libraries modify arguments of created processes
                        in a way that makes them unrecognizable to the Svace
                        code that detects "interesting" processes, the Svace
                        library should be prepended instead, ensuring that it
                        sees the same arguments that were passed by the
                        application. In particular, this is needed for
                        Scratchbox environment.
  --disable-path-sens-csa
                        Disable all path sensitive checkers of Clang Static
                        Analyzer.
  --disable-comp        Disable all compiler addons
  --disable-misc        Disable all non-compiler addons
  --clang-opts CLANG_OPTS
                        Add specified options to the Clang and Clang Static
                        Analyzer run by Svace. The options should be separated
                        by ';'.
  --spotbugs-opts SPOTBUGS_OPTS
                        Add specified options to the SpotBugs run by Svace.
                        The options should be separated by ';'.
  --tags-javac-opts TAGS_JAVAC_OPTS
                        Add specified options to the tags-javac run by Svace.
                        The options should be separated by ';'.
  --max-tags-javac-jobs MAX_TAGS_JAVAC_JOBS
                        Specify maximum number of tags-javac processes that
                        Svace may run concurrently. By default, no artificial
                        limit is set, so it is bounded only by the concurrency
                        level of the build system being intercepted.
  --enable-csa-stat     Generate '*.plist.times' files containing the running
                        time of CSA checkers (in ms) in the build directory.
  --keep-intermediate-source
                        If --enable-csa-deps is specified, do not remove
                        partially preprocessed '.source' files from the build
                        directory after archiving them. This option is
                        intended for easier debugging.
  --run-tags-javac-via-intercepted-java
                        Run tags-javac via a JDK that was used to run the
                        intercepted javac instead of the JRE bundled with
                        Svace. Note that this option is ignored for
                        compilations performed via javac 11 or older. The main
                        use case for this option is to support annotation
                        processors compiled for Java newer than 11 (i.e., the
                        ones that can't be run on the JRE from Svace). Note
                        that other Java compilers are not supported by this
                        option.
  --enable-mount-ns-workaround
                        If the build process enters a mount namespace and then
                        creates new mount points under non-shared mount
                        points, those new mount points are not visibile in the
                        parent mount namespace, preventing top-level Svace
                        processes from accessing affected paths. This option
                        enables a workaround. Currently, it works only if the
                        build process doesn't also enter a PID namespace.
  --enable-if-info, --disable-if-info
                        Dump information about if/else block boundaries with
                        regards to source code line numbers. Information is
                        stored in speficic JSON format within a project build
                        directory.
  --hash-ar-content     Calculate archive hash based only on names of files in
                        the archive, excluding timestamp, UID, GID and
                        content. Use in case of undeterministic mode of ar or
                        ranlib and in case of prebuilt archives with prebuilt
                        object files (that may differ because of another
                        platform etc.). DO NOT USE in case of rebuilding the
                        same archive more than once in the same build (e.g.
                        debug and release mode).
  --preserve-build-order
                        Store compilation data in the same order as it's
                        received by Svace hash server. If the build order is
                        deterministic, but the build data is different between
                        runs, this may be useful to ensure that the data is
                        always processed in the build order by build object
                        consumers. By default, the build order is not
                        preserved, and build artifacts are usually sorted by
                        content hash before storage.
  --incremental         Mark current build to be incremental. Requiers full
                        build to be run with '--enable-rebuild' option.
  --disable-hash-server
                        Disable Svace hash server, making it impossible to use
                        the build data on the analysis phase. This option is
                        for advanced users only.
  --disable-java-bytecode-gen
                        Don't generate Java bytecode used for analysis by
                        Svace and SpotBugs. This option is for advanced users
                        only.
  --enable-huge-source-workaround
                        Clang can't handle translation units larger than 2 GB
                        after preprocessing because it uses signed 32-bit
                        integer type internally for identifying source
                        locations. Sometimes such huge TUs occur in practice
                        because the same autogenerated header file is included
                        multiple times without guards. In this case source
                        locations are allocated for each inclusion, which may
                        cause an overflow resulting in a hang or crash. This
                        option makes it so source locations are allocated only
                        once per header file, which may help avoid the
                        overflow in this case. This option is incompatible
                        with '--enable-csa-deps'.

deprecated options (may be removed in a future release):
  --clear-bitcode-dir   An alias for --clear-build-dir.
  --memory HASH_SERVER_MEMORY
                        An alias for --hash-server-memory.
  --enable-findbugs, --disable-findbugs
                        Aliases for --enable-spotbugs and --disable-spotbugs.
  --findbugs-memory SPOTBUGS_MEMORY
                        An alias for --spotbugs-memory.
  --findbugs-opts SPOTBUGS_OPTS
                        An alias for --spotbugs-opts.
  --enable-jack-interception
                        Has no effect (for backward compatibility only)

Environment variables:
  SVACE_DIR             Overrides the default value for --svace-dir
  SVACE_ENABLE_CSA_STAT
                        Overrides the default value for --enable-csa-stat.
                        Must be set to 'yes' or 'no'.

svace config

Usage: svace config [OPTIONS] [<key> [<value>]]
       svace config [OPTIONS] --unset <key>

Manage configuration settings. In the first variant (without --unset), if 
only <key> is specified, get current value assigned to that key (--parents 
must be specified to take system-wide and user-specific configuration into 
account). If both <key> and <value> are specified, set <key> to <value>. For 
boolean keys, possible values are 'true' and 'false'. Some keys that control 
internal (development) settings are 'hidden' and don't show by default, but 
can be listed with --show-hidden.

Common config options (shared by 'warning' and 'config' tools):
  --global           : Work with user-specific configuration
                       ~/.svace/<config-file>, rather than the local
                       configuration $SVACE_DIR/<config-file>
  --system           : Work with system-wide configuration
                       /path/to/distro/config/<config-file>, rather than the
                       local configuration $SVACE_DIR/<config-file>
  -f, --file FILE    : Use specified config file instead of the one implied by
                       options --global, --system, or current svace dir.
                       If FILE is '-', read from stdin and write to stdout
                       (implies --quiet).
  --unset            : Remove the entry for specified key from config file (so
                       that the default value or value specified in parent
                       config files will be used instead).
  --unset-all        : Clear the config file.
  -l, --list         : List the entries specified in config file(s).
  -a, --all          : List entries for all keys, including those not specified
                       in config files. Don't list hidden keys, unless 
                       --show-hidden is specified. Implies --parents.
  --show-hidden      : When listing keys with --all or --list, show hidden keys
                       as well.
  -i, --info         : For each listed key, print a short description.
  -p, --parents      : When reading from config file, take into account the
                       settings specified in parent files. By default, apply
                       system-wide, user-specific and then Svace directory
                       or explicitly specified settings to form the list of
                       modified settings and their values.
                       If --global is specified, apply only system-wide and
                       user-specific settings; if --system is specified,
                       apply only system-wide settings.
  --svace-dir PATH   : Specify a Svace directory, overriding current directory
                       and $SVACE_DIR environment variable.
  -q, --quiet        : Only print error messages (to stderr) and specifically
                       requested output (to stdout).
  --get-val          : Only print the value of specified key (without 'key = ').

svace warning

Usage: svace warning [OPTIONS] [<warn-type> [<state>]]
       svace warning [OPTIONS] --unset <warn-type>

Manage warning settings (which warning types are enabled/disabled). In the
first variant (without --unset), if only <warn-type> (key) is specified, get
current state (value) of that warning type (--parents must be specified to
take system-wide and user-specific configuration into account). If both
<warn-type> and <state> are specified, set <warn-type> to <state>. Possible
values for <state> are 'true', 'false' and 'hidden' (disables a warning type
and hides it from output of '--all').

Special warning name 'all' can be used to enable/disable all warning types
at once, except for warning types hidden by default.
Use special warning name 'hidden' to enable/disable warning types hidden by
default.

Common config options (shared by 'warning' and 'config' tools):
  --global           : Work with user-specific configuration
                       ~/.svace/<config-file>, rather than the local
                       configuration $SVACE_DIR/<config-file>
  --system           : Work with system-wide configuration
                       /path/to/distro/config/<config-file>, rather than the
                       local configuration $SVACE_DIR/<config-file>
  -f, --file FILE    : Use specified config file instead of the one implied by
                       options --global, --system, or current svace dir.
                       If FILE is '-', read from stdin and write to stdout
                       (implies --quiet).
  --unset            : Remove the entry for specified key from config file (so
                       that the default value or value specified in parent
                       config files will be used instead).
  --unset-all        : Clear the config file.
  -l, --list         : List the entries specified in config file(s).
  -a, --all          : List entries for all keys, including those not specified
                       in config files. Don't list hidden keys, unless 
                       --show-hidden is specified. Implies --parents.
  --show-hidden      : When listing keys with --all or --list, show hidden keys
                       as well.
  -i, --info         : For each listed key, print a short description.
  -p, --parents      : When reading from config file, take into account the
                       settings specified in parent files. By default, apply
                       system-wide, user-specific and then Svace directory
                       or explicitly specified settings to form the list of
                       modified settings and their values.
                       If --global is specified, apply only system-wide and
                       user-specific settings; if --system is specified,
                       apply only system-wide settings.
  --svace-dir PATH   : Specify a Svace directory, overriding current directory
                       and $SVACE_DIR environment variable.
  -q, --quiet        : Only print error messages (to stderr) and specifically
                       requested output (to stdout).
  --get-val          : Only print the value of specified key (without 'key = ').

Warning tool specific options:
  --preset NAME      : Work with specific preset of options

Warning type properties (displayed when option --info is given;
see User Guide for more details):
  Situation  : What kind of situation is indicated by the issue.
               Possible values:
                 Quality
                 Security
                 CodingStyle
                 Suppressed
                 Duplicate
  Severity   : Potential danger represented by the issue, if it's correctly
               detected. Possible values:
                 Critical
                 Major
                 Normal
                 Minor
                 Undefined
  Reliability: How often the issues of this type are detected correctly
               (in different projects). Possible values:
                 VeryHigh
                 High
                 Average
                 Low
                 VeryLow
                 Unknown
  Language   : For which languages warnings of this type are detected.
               Possible values:
                 C_CPP
                 JAVA
                 KOTLIN
                 CSHARP
                 GO
                 NONE
  Detection tools: Where the checker for the issue is implemented.
               Possible values:
                 SvEng
                 SvaceCppSpecific
                 CSA
                 SpotBugs
                 Goa
                 TagsJavac
                 Roslyn
                 Kotlinc

Examples:
# Get the state of warning type DEREF_AFTER_NULL, taking parent configuration
# into account:
    svace warning -p DEREF_AFTER_NULL

# Disable DEREF_AFTER_NULL for all analysis invocations by current user:
    svace warning --global DEREF_AFTER_NULL false

# List all warning settings specified for current user, including a short
# description for each warning type:
    svace warning -lpi --global

# Dump all information about the configuration that would be used during
# analysis:
    svace warning -lap --show-hidden

svace analyze

This is the main analysis tool. It takes as input the data produced by 'svace build' and generates analysis result files. Command line options are as follows:

usage: svace analyze [options]

Analyze the selected project directory with Svace.
By default, a project directory based on the current working directory 
is selected, and analysis is performed for the last build object produced by
'svace build', which is specified in file <project-dir>/bitcode/build-object.
Use '--svace-dir' to specify a different project directory and '--build'
to specify a different build object.

optional arguments:
  -h, --help            show this help message and exit
  --svace-dir DIR       Specify a Svace directory, overriding current
                        directory and SVACE_DIR environment variable.
  -b HASH, --build HASH
                        A build object to be analyzed. By default, the last
                        build object produced by 'svace build' is used.
  -n NAME, --name NAME  Associate given name with the analyzed project (used
                        for naming files with results and some other files).
                        By default, the name of the project directory is used.
  --memory NUM_MB       Specify maximum amount of RAM (in MB) that Svace may
                        use for analysis. More precisely, this option controls
                        the maximum size of JVM heap. If set to 'auto' (the
                        default), Svace attempts to detect the maximum usable
                        JVM heap size at the time of analysis start and uses
                        the value close to the detected maximum.
  --enable-language LANG, --disable-language LANG
                        Enable analysis for the specified programming
                        language. Valid values are: all, cxx, go, java,
                        kotlin. Enabling a language also enables working with
                        the relevant tools (e.g., enabling Java turns on
                        analysis with SpotBugs and tags-javac). Default values
                        set by this option are overridden by --import-<tool>,
                        --skip-import-<tool> and
                        --skip-<lang_or_tool>-analysis options. By default,
                        analysis of C/C++ and Java is enabled.
  --cross-language-analysis, --cross-lang-analysis
                        Perform cross language analysis. This means Svace will
                        analyze mixed (Java and Kotlin) project as single
                        target.
  --target TARGET       Select the target architecture of C/C++ code to
                        analyze. If it's set to 'all' (the default), each
                        target is analyzed in turn independently of other
                        targets. Valid values are: all, aarch64, arm, hexagon,
                        mips, mips64, powerpc, powerpc64, riscv32, riscv64,
                        sparc, sparc64, x64, x86. Note that setting this
                        option to a non-default value disables analysis of all
                        languages except C/C++.
  --preset NAME         Use the requested warnings preset during the analysis.
  --server              Enable server analysis mode. In this mode computed
                        function annotations and possibly other information
                        will be saved to disk to be used by the annotation
                        server for supporting the client fast analysis mode.
  --client              Enable fast analysis mode on the client desktop. In
                        this mode, the data required for the unknown functions
                        analysis will be queried from the annotation server.
  --prefer-disk-cache   More actively use disk for reducing memory
                        consumption. Enabling this option may lead to
                        performance degradation and increasing requirements to
                        disk space.
  --import-csa, --skip-import-csa
                        Import Clang Static Analyzer results generated at the
                        build phase. Has no effect if CSA is run at the
                        analysis phase (see --skip-csa-analysis).
  --import-spotbugs, --skip-import-spotbugs
                        Import analysis results of SpotBugs generated at the
                        build phase. Has no effect if SpotBugs is run at the
                        analysis phase (see --skip-spotbugs-analysis).
  --import-tags-javac, --skip-import-tags-javac
                        Import analysis results of tags-javac generated at the
                        build phase. Has no effect if tags-javac is run at the
                        analysis phase (see --skip-tags-javac-analysis).
  --import-kotlinc, --skip-import-kotlinc
                        Import analysis results of Kotlin compiler generated
                        at the build phase. Has no effect if kotlinc is run at
                        the analysis phase (see --skip-kotlinc-analysis (not
                        implemented yet)).
  --skip-c-analysis     Don't analyze C/C++ code with Svace engine. Note that
                        Clang Static Analyzer is not affected by this option.
  --skip-java-analysis  Don't analyze Java code with Svace engine. Note that
                        Spotbugs and tags-javac are not affected by this
                        option.
  --skip-csa-analysis   Don't analyze C/C++ code with Clang Static Analyzer.
                        You may still see CSA results if it was enabled at the
                        build phase and its results were imported.
  --skip-spotbugs-analysis
                        Don't analyze Java code with SpotBugs. You may still
                        see SpotBugs results if it was enabled at the build
                        phase and its results were imported.
  --skip-tags-javac-analysis
                        Don't analyze Java code with tags-javac. You may still
                        see tags-javac results if it's checkers were enabled
                        at the build phase and its results were imported.
  --skip-sveng-analysis
                        Don't run Svace engine analysis.
  --skip-jar-files      Don't analyze jar files during Java code analysis with
                        Svace engine (equivalent to setting USE_JAR_FILES
                        config option to 'false').
  --csa-opts OPTS       Add specified options to the Clang Static Analyzer run
                        by Svace. The options should be separated by
                        semicolons (';'). To specify a literal semicolon,
                        prepend a backslash ('\') to it. To specify a sequence
                        of literal backslashes before a literal semicolon,
                        repeat each of the literal backslashes twice.
  --set-config KEY=VALUE
                        Set the value of config option KEY to VALUE for this
                        analysis run only. Takes precedence over config files.
  --set-warn WARN=(true|false)
                        Enable or disable warning type WARN for this analysis
                        run only. Takes precedence over config files.
  -w FILE, --warnings FILE
                        Load warning settings (information about
                        enabled/disabled warning types) from FILE instead of
                        warn-settings.txt from Svace project directory. Note
                        that defaults from system and global settings are
                        still applied as usual.
  -q, --quiet           Show error messages only (isn't fully supported).
  -v, --verbose         Show detailed information about analysis and its
                        status (isn't fully supported).
  --version             Show Svace engine version information and exit. If
                        used together with '--quiet', only version number in
                        X.Y.Z format is printed. The Svace engine version is
                        normally the same as the version of the Svace
                        distribution as shown by 'svace --version'.

experimental options:
  -t HASH, --task HASH  A task object to be analyzed.
  --raw-files           Analyze files with intermediate representation in the
                        build directory ($SVACE_DIR/bitcode by default)
                        instead of analyzing a build object. This option may
                        be useful for debugging, but normally shouldn't be
                        used.
  --resume              Enable specific mode, which make possible to resume
                        analysis from the point it has been interupted.
                        Specify the key both to make this option possible or
                        to continue analysis.
  --inter-project-dir DIR
                        Specify a dir for storing annotations that may be used
                        for analysis other projects.
  --incremental         Enable incremental analysis mode. It implents the same
                        behavior as a --client option. However, the results of
                        analysis is almost the same as for full analysis.
                        Demand a project to have been analyzed with server
                        option yet.
  --build-dir DIR       Specify a build directory produced by 'svace build' to
                        use for analysis. The default is $SVACE_DIR/bitcode.
                        Valid only together with --raw-files.
  -s DIR, --source DIR  Search for source code in DIR. Project directory is
                        used by default (as specified, even if the actual
                        Svace directory is its subdirectory .svace-dir). Valid
                        only together with --raw-files.
  -o DIR, --output DIR  Save analysis results in DIR. By default, the results
                        are saved in $SVACE_DIR/analyze-res. The analysis
                        result files are $PRJ_NAME.svres and $PRJ_NAME.txt,
                        where $PRJ_NAME is the name of the analyzed project.
                        Valid only together with --raw-files.
  --fix                 Run autofix during analysis.
  --autofix-backend {svace}
                        Autofix backend to use. The default is 'svace'.
  --emit-autofix-input  Emit autofix input as a separate file (for debug
                        purposes).

deprecated options (may be removed in a future release):
  --import-findbugs     An alias for --import-spotbugs.
  --skip-import-findbugs
                        An alias for --skip-import-spotbugs.
  --skip-findbugs-analysis
                        An alias for --skip-spotbugs-analysis

svace history

svace history list   [--svace-dir <project-dir>] [--branch <branch>]
                     [--class <warning type>] [--status <warning status>]
svace history update [--svace-dir <project-dir>] [--branch <branch>]
                      --warning <warning ID> [--user <user name>]
                     [-status <warning status>] [--comment <comment>]
svace history import [--svace-dir <project-dir>] [--branch <branch>]
                     (--task <task ID> | --build <build ID>)
                      --results <results ID> [--name <snapshot name>]
                     [--user <user name>]
svace history branch (list |
                      clone --target <branch name> [--source <branch name>] |
                      delete --branch <branch name> [--force] |
                      sync <branch name> <branch name>)
                     [--svace-dir <project-dir>] [--branch <branch>]
svace history merge-svres svres-id...
svace history split-build build-id

Interact with a warning database. Allows to import new analysis results,
list analysis results and modify warning states from the command line.

Common options:
  --svace-dir PATH	: Svace project directory to work with.
                  	  If not set, current working directory will be used.
  --branch NAME		: History branch to work with.
               		  If not set, default ('master') branch will be used.

Operations and their options:
  list			: Show list of actual warnings in a history branch.
      			  These warnings can be filtered.
    --class NAME	: Display only warnings of selected class.
                	  Can be used several times, showing multiple warning
                	  classes. If not set, all warnings are shown.
    --status STATUS	: Display only warnings having selected status.
                   	  Can be used several times, showing warnings of
                   	  multiple statuses. If not set, all warnings are shown.
    --format FORMAT	: Format output for each warning according to
                   	  a format string. Supported format specifiers:
                   	  %h: Warning ID (hash)
                   	  %c: Warning class
                   	  %s: Warning status
                   	  %m: Warning message
                   	  %l: Warning location
                   	  %u: User comment
                   	  %A: User-defined attributes
    --current-snapshot VAL	: If VAL is false, display only warnings that
                   	  didn't appear on the current (last) snapshot
                   	  (but were detected on one of the old snapshots).
                   	  If it's true, display only warnings detected on the
                   	  current snapshot (this is the default).
    --previous-snapshot VAL	: If VAL is false, display only warnings that
                   	  didn't appear on the previous snapshot
                   	  (but were detected either on one of the old snapshots,
                   	  or on the current snapshot).
                   	  If it's true, display only warnings detected on the
                   	  previous snapshot.

  update		: Modify a warning in the history storage.
    --user NAME		: Username related to this warning modification.
               		  If not set, current user name will be used.
    --warning ID	: The 32-symbol ID for warning which must be updated.
    --status STATUS	: New status for the selected warning.
                   	  May be one of 'bug', 'scope', 'goal', 'unclear' or
                   	  'default' (case-insensitive).
                   	  Other statuses are interpreted as 'default'.
    --comment STRING	: New comment string for the selected warning.

  import		: Import analysis results into history storage.
        		  When neither build/task nor results object are specified,
        		  import the last analysis results.
    --user NAME		: Username related to this warning modification.
               		  If not set, current user name will be used.
    --results ID	: The 32-symbol ID for the imported analysis results.
    --build ID		: The 32-symbol ID for the build which was analyzed
              		  to produce imported analysis results.
    --task ID		: The 32-symbol ID for the task which was analyzed
             		  to produce imported analysis results.
    --name NAME		: Snapshot name related to these analysis results.

  import-data		: Internal tool mostly for debugging.
             		  Allows to import analysis results and source code snapshots,
             		  into svace storage system.
    --type		: 'svres', 'build', 'source-build' or 'empty-build'.
          		  'svres' allows you to import analysis results in svres format,
          		  'empty-build' produces build-object with no data in it,
          		  'build' imports build object previously exported using
          		  Svace 'export-build' command, 'source-build' allows you to import
          		  some directory as a source code snapshot. The resulting build-object
          		  will obviously contain no bitcode, so it won't be analyzable;
          		  however it can be useful for importing data into history system.
    --path		: path to file (if importing 'svres') or directory (if importing
          		  a source code snapshot or build object) you want to import.
    --orig-path		: used for 'source-build' only, and is optional. Indicates
               		  the path where the imported source tree should be available at.
               		  E.g.: you have file /home/user/project/file.c, you use:
               		  --path /home/user/project/, --orig-path /var/build
               		  the file will be imported and used by history system
               		  like it was located at /var/build/file.c
               		  If you are under *nix OS and you want to emulate build-object
               		  generated by windows system, change orig-path this way:
               		  'C:\Some\Dir\' => '/c_/Some/Dir/', and also check next flag.
    --with-dxr		: used for 'source-build' only, and is optional. Allows to provide
              		  a directory with source code markup in csv format. Svace requires
              		  file names in the same format svace generates dxr files itself. Also
              		  Svace requires empty .csv.stamp files along with .csv data files.
    --merge-metrics	: used for 'build' only, and is optional. If set to 'true' merges
                 		  imported build object metrics with the current ones.
    --move		: used for 'build' only, and is optional. If set to 'true' moves
          		  imported files instead of copying them. This allows to speed up
          		  the import but the export folder will be cleared after this.

  branch		: Manage branches. Must be followed by one of
        		  the following sub-commands:
    list		: List all branches in the project directory
        		  (including remote branches).
    clone		: Create a new branch and optionally makes its state
         		  equal to another branch.
      --target NAME	: Branch name to be created.
      --source NAME	: Branch to be cloned.
                   	  If not set, created branch will have no content.
    delete		: Delete specified branch.
      --branch NAME	: Name of the branch to be deleted.
      force		: Allows to delete 'master' branch.
                   	  (svace history branch delete force --branch master)
    sync NAME NAME	: Sync warning states from two given branches.

  merge-svres		: Takes multiple analysis results and merges them all
        		  in one large analysis results.
  split-build		: Takes build object and splits it into multiple build objects
        		  where each resulting build object has only some target-related data.

Examples:
# List warnings of class MEMORY_LEAK with Goal and Default statuses:
    svace history list --class MEMORY_LEAK --status Default --status Goal

# List warnings of class MEMORY_LEAK that disappeared on the last snapshot:
    svace history list --class MEMORY_LEAK --current-snapshot false \
                       --previous-snapshot true

# Change status of a selected warning:
    svace history update --user developer1 --warning 123..132 --status Bug \
                         --comment 'Array index isn't checked before access'

# Import existing analysis results into history database:
    svace history import --user developer1 --build 123..231 --results 323..321'

# Clone existing branch into a new one:
    svace history branch clone --source master --target backports_2.0

svace server

usage: svace server [--server-dir DIR] <subcommand> [args]

optional arguments:
  --server-dir DIR  Specify a Svace server directory. By default, the current
                    directory is used.
  --help            Show this help message and exit.

subcommands:
  subcommand
    init            Create a Svace server directory.
    start           Start the history access server.
    single-start    Start the history access server in single-project mode.
    admin           Manage a Svace server.
    show-api-docs   Display documentation for Svace history API.

Tutorial

This section demonstrates the process of using the tool with an example (analysis of proftpd-1.3.3).

Building source code

Let's assume that Svace is located in ~/svace/, on an Ubuntu system.

A copy of the proftpd-1.3.3 distributive can be downloaded from the Internet at ftp://ftp.proftpd.org/distrib/source/proftpd-1.3.3.tar.bz2. Extract the archive in ~/projects/proftpd-1.3.3/

The package can be built using configure/make. To obtain LLVM bitcode files for analysis by svace, svace project folder must be initialized first and then building commands need to be wrapped in 'svace build' command as follows:

 cd ~/projects/proftpd-1.3.3
 ./configure
 ~/svace/bin/svace init 
 ~/svace/bin/svace build make

If the operation completes successfully, a text like the following will be displayed by 'build':

Now Svace will preprocess captured data.
Processing source code markup data...
[**********************************************************************] 100%
Assembled build object: [BUILD]6715d4e4c908f8e62a54f174796282c48ce2d3a5
  83 C/C++ units are ready.

As a result, the folder ~/projects/proftpd-1.3.3/.svace-dir/bitcode/ should now contain files with intermediate representation, for example the file

 ~/projects/proftpd-1.3.3/.svace-dir/bitcode/auth.e7d9dbb866bdbd6c2456bf8f3212d727.bc

Further analysis will only require files within Svace project folder (~/projects/proftpd-1.3.3/.svace-dir), so the other byproducts of the building process can be safely removed.

Performing analysis

Assuming that folder ~/projects/proftpd-1.3.3 contains the svace project folder with intermediate representation files obtained on the previous step, analysis can be launched with the following command:

 ~/svace/bin/svace analyze --svace-dir ~/projects/proftpd-1.3.3

As a result (it should take a couple of minutes), two files will be created:

 ~/projects/proftpd-1.3.3/.svace-dir/analyze-res/proftpd-1.3.3.txt
 ~/projects/proftpd-1.3.3/.svace-dir/analyze-res/proftpd-1.3.3.svres

First file should contain (for example) the following warning of type DEREF_OF_NULL:

* DEREF_OF_NULL: Pointer 'symhold' that can have only NULL value (checked at line 152), is dereferenced at line 153.
    dereference at mod_ls.c:153
    null at mod_ls.c:152
    source line: "*symhold = show_symlinks_hold;"

Corresponding source file fragment (from ~/projects/proftpd-1.3.3/modules/mod_ls.c:152):

 if (!symhold)
   *symhold = show_symlinks_hold;

Viewing the results

For example, consider the warning NULL_AFTER_DEREF/proftpd-1.3.3/auth.c:1227. Below is the corresponding excerpt from the plain text file ~/projects/proftpd-1.3.3/.svace-dir/analyze-res/proftpd-1.3.3.txt:

* NULL_AFTER_DEREF: Pointer 'login_name' which was dereferenced at line 1222 is compared to NULL value at line 1227.
    null check at auth.c:1227
    dereference at auth.c:1222
    source line: "if ((!login_name || !anon_c) &&"

The relevant part of the source code is as follows:

1222: if (*login_name &&
          auth_alias_only &&
          *auth_alias_only == TRUE)
        *login_name = NULL;

1227: if ((!login_name || !anon_c) &&
          anon_name) {
        *anon_name = NULL;
      }

On line 1222, variable 'login_name' is dereferenced. If 'login_name' is NULL, this will be a null pointer dereference. On line 1227, this pointer is compared to NULL, which suggests that it indeed can be NULL on line 1222. If it can't, then the check on line 1227 is redundant.

Warning types

Warning types classify individual warnings (issues) emitted by Svace. Each warning type specifies the kind of defect being sought, typical situations in which such issues are found, and possible sources of false positives. Some of the warning types have subtypes, allowing more fine-grained classification of the detected issues.

Kinds of warning types

Each warning type is characterized by several properties, which can be inspected by running the warning tool with option --info. These properties can be helpful when deciding which warning types to inspect and when interpreting the results classified under various warning types.

Severity

Severity is an estimate for the potential danger represented by issues of the warning type that are detected correctly. Possible values of this property are Critical, Major, Normal, Minor and Undefined.

Reliability

Reliability is an estimate for how often the issues of a given type are detected correctly. The estimate is based on results obtained on many different projects, and actual reliability of results on a given project may significantly deviate from the average. Possible values are VeryHigh, High, Average, Low, VeryLow and Unknown. When there are only a few issues detected for a warning type, it may be worthwhile inspecting even warning types rated Low or VeryLow, but for warning types that are frequently detected, focusing on results of VeryHigh, High and Average reliability is more important.

Type of detected situations

In addition to normal warnings that indicate a defect, there are warnings with different aims, which are described with this property. Suppressed and Duplicate warning types normally shouldn't be used, but are included for completeness.

  • Quality: Warnings of this type indicate defects that can lead to errors and should be fixed. An ideal checker for such warning types should in principle be able to avoid false positives (compare with Suppressed).
  • Security: Warnings of this type focus on potential vulnerabilities that may be exploited by a malicous attacker.
  • CodingConvention: Coding convention warnings indicate situations where a certain coding convention is violated. Violation of a coding convention doesn't necessarily lead to an error, and so should only be fixed if the coding convention is encouraged or enforced for the code being analyzed. An ideal checker for such warning types should in principle be able to avoid false positives, but the issues are likely to be of no interest to the projects that don't follow the coding convention.
  • Suppressed: Issues emitted with suppressed warning types are those that could've been emitted with a normal (non-suppressed) warning type, but were found to have some flaw that made it probable that they would be false positives. Rather than hiding such issues entirely, we instead change their warning type to a related suppressed warning type. Note that different suppressed warning types may have different reliability, but unlike normal warning types, their reliability often can't be improved even in principle, and is often low or very low "by design". In rare cases, reliability of suppressed warnings may be acceptable, in which case it may be worthwhile to inspect their results.
  • Duplicate: Warnings of this type are duplicates of other warnings, and so shouldn't normally be inspected, even if they have high reliability.

Detection tool

Most Svace checkers are implemented in the main analysis framework, which is indicated by SvaceMain detection tool property of the warning type. A few of the checkers that detect simpler situations are implemented in Clang, and have SvaceClang as their detection tool. Issues imported from SpotBugs are marked as having SpotBugs as the detection tool (and have warning type prefix FB.).

Warning subtype specifiers

Some of the warnings have common subtypes, that are indicated by adding a suffix after a dot to the warning type. For example, the TAINTED_INT warning type has a suppressed subtype TAINTED_INT.MIGHT.

.MIGHT

This subtype indicates that the checker knows of ways in which the warning might be false, and of ways in which the warning might be true, but can't prove it either way. This is a "weaker" warning subtype, and sometimes the results falling under it should be skipped, but sometimes the detected issues turn out to be correct. Since the checker can't prove that the issues are correct, even under the heuristic assumptions used to find them, reliability of these warning types is generally lower and can't be significantly improved.

.PROC

This subtype specifies that the runtime error or memory corruption happens inside a user-written procedure called from the code that causes the problem. In other words, the problem is caused by incorrect (unsafe) invocation of a procedure.

.GLOBAL

This subtype indicates that memory locations involved in these warning reports have global scope.

.MINOR

This subtype indicates that severity of warning may be less than for major type.

.STRICT

This subtype indicates that a warning is reported may require very strict error policy to analyzed source code.

.EX

This subtype indicates that a warning is reported by an extended version of the checker.

Null pointer dereference

DEREF_OF_NULL

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalHighC/C++ Java C#Yes

This checker finds situations where a pointer is dereferenced, but can only have NULL value, and so the operation of dereference can never be run without causing a runtime error. A special case where the NULL value is explicitly assigned is categorized as DEREF_OF_NULL.CONST.

More generally, checkers in the DEREF_OF_NULL group find situations where a dereferenced pointer can be assigned NULL value on one of the possible execution paths.

Subtype .PROC may apply to the warnings of this group.

Example (C/C++)

 struct process {
   char* user;
 };

 void test(struct process* ps, FILE* log) {
   if(!ps)
     fprintf(log, "No information for user: %s", ps->user);
 }

Dereference of structure pointer ps, if reachable, can only lead to a null pointer dereference.

See also

DEREF_OF_NULL.EX

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++ Java KOTLINYes

This checker is similar to DEREF_OF_NULL checker, but can find situations where a pointer is assigned to NULL under some condition and then dereferenced under another condition which is not incompatible with the first one.

Example (Kotlin)

import java.io.File

fun handleCollection(collection: Collection<Any>?) {
    for (elem in collection!!) {
        // ...
    }
}

fun handleCollectionCorrect(collection: Collection<Any>?) {
    collection?.forEach { elem ->
            // ...
    }
}

fun example(f: File) {
    val files = f.listFiles()?.asList()
    handleCollection(files)
}

fun possibleFix(f: File) {
    val files = f.listFiles()?.asList()
    handleCollectionCorrect(files)
}

Function 'example' illustrates the defect: 'files' may be null, but it will be dereferenced inside 'handleCollection' function call. Function 'possibleFix' illustrates a possible fix: use safe implementation 'handleCollectionCorrect' to iterate over collection. Safe call of 'forEach' is used inside 'handleCollectionCorrect' function.

DEREF_OF_NULL.CONST

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalHighC/C++ Java KOTLINYes

This checker finds situations where a pointer is dereferenced, but can only have NULL value, because it was explicitly assigned a NULL value.

Example

 void test() {
   int* ptr = NULL;
   int x;

   [...]

   x = *ptr;
 }

Example (Kotlin)

class Holder(str: String) {
    var nullable: Int? = null
}

fun example() {
    val h = Holder("Create and forget to init 'nullable'")
    h.nullable!!.dec()
}

fun possibleFix() {
    val h = Holder("Create and forget to init 'nullable'")
    h.nullable?.dec()
}

Function 'example' illustrates the defect: 'dec' is called for value which may be null. Function 'possibleFix' illustrates a possible fix: use safe call.

False positives

Sometimes, the pointer is assigned a non-null value as a side effect of a function call. If the analysis is unable to see such a side effect (normally, side effects are analyzed), this warning may be emitted incorrectly.

DEREF_OF_NULL.ASSIGN

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++ Java KOTLINYes

This checker finds situations where a pointer is assigned NULL value, and is subsequently dereferenced. In these situations, the dereferenced pointer is not necessarily NULL, but a pointer that was assigned NULL value is necessarily dereferenced.

Example (C/C++)

 void proc(int* p, int flag) {
   if(flag==7)
     p = 0; // NULL value assigned to 'p'
   
   *p = 7; // if NULL value is assigned to 'p', it's necessarily dereferenced here
 }

Example (Kotlin)

data class Wrapper(val value: Int)

fun example(w: Wrapper?): Int {
    val mayBeNull = w?.value
    return mayBeNull!!
}

fun possibleFix(w: Wrapper?): Int? {
    val mayBeNull = w?.value
    return mayBeNull
}

Function 'example' illustrates the defect: 'mayBeNull' may have null value and is casted to non-nullable type by '!!' operator. Function 'possibleFix' illustrates a possible fix: return nullable type.

See also

DEREF_OF_NULL.COND

Situation Severity Reliability Supported languages Enabled by default
QualityNormalHighC/C++ JavaYes

This checker finds situations where a function conditionally dereferences a pointer, and this function is called with NULL assigned to that pointer.

Example

 void foo(int x, int* p) {
   if(x>7)
     return;
   *p = 3;
 }
 
 void main() {
   foo(30, NULL);
 }

False positives

Sometimes, the condition under which the function dereferences the pointer is not satisfiable at the call site where NULL value is assigned to that pointer. The checker emits the warning even if this possibility wasn't ruled out, which leads to false positives in such cases.

See also

DEREF_OF_NULL.RET

Checkers for this warning group find situations where a pointer is unconditionally dereferenced, that was returned by a function that returns NULL on some the paths, for example:

 int* p = foo(); // foo() sometimes returns NULL!
 x = *p

Depending on the kind of function that returns such pointer, one of the following subtypes of this warning is emitted:

  • DEREF_OF_NULL.RET.ALLOC - if the function allocates memory, and returns NULL when out of memory;
  • DEREF_OF_NULL.RET.LIB - if this is a library function not concern with memory allocation, that is known to return NULL in case of an error, for example fopen();
  • DEREF_OF_NULL.RET.USER - for functions implemented in the analyzed code, where returning of NULL is observed explicitly.

DEREF_OF_NULL.RET.ALLOC

Situation Severity Reliability Supported languages Enabled by default
QualityNormalHighC/C++No

This warning finds situations where a pointer returned by a memory allocation function, such as malloc(), is dereferenced without being checked for NULL value.

Example

 void test() {
   char* buf = (char*)malloc(10);
   buf[0] = '\0';
 }

See also

DEREF_OF_NULL.RET.LIB

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++ Java KOTLIN C#Yes

This warning finds situations where a pointer returned by a library function, such as fopen(), is dereferenced (accessed by other library functions) without being checked for NULL value.

Following is the list of library functions that are recognized by this checker as being able to return NULL value for reasons not under user's control:

 localtime
 fdopen
 fopen
 popen
 getenv
 opendir
 dlopen
 dlsym
 freopen
 tempnam
 tmpfile
 tmpnam
 ptsname
 getutent
 getutid
 getutline
 pututline
 getcwd
 getwd

The 'DEREF_OF_NULL.RET.LIB.PROC' subtype specifies that DEREF_OF_NULL.RET.LIB happens inside a user-written procedure called from the code that causes the problem. In other words, the problem is caused by incorrect (unsafe) invocation of a procedure.

Example (Kotlin)

import java.io.File

fun example(f: File) = f.parentFile.listFiles()

fun possibleFix(f: File) = f.parentFile?.listFiles()

fun handleFiles(arr: Array<File>?) = arr!!.count { f -> f.isFile && !f.isDirectory }

fun exampleProc(f: File) = handleFiles(f.listFiles())

fun handleFilesCorrect(arr: Array<File>?) = arr?.count { f -> f.isFile && !f.isDirectory } ?: 0

fun possibleFixProc(f: File) = handleFilesCorrect(f.listFiles())

Function 'example' illustrates the 'DEREF_OF_NULL.RET.LIB' defect: property 'parentFile' may return null, which will be dereferenced by 'listFiles' call. Function 'possibleFix' illustrates a possible fix: use safe call of 'listFiles' function.

Function 'exampleProc' illustrates the 'DEREF_OF_NULL.RET.LIB.PROC' defect: call of 'listFiles' function may return null, which will be dereferenced by call of user defined function 'handleFiles'. Function 'possibleFixProc' illustrates a possible fix: use safe implementation 'handleFilesCorrect' to iterate over files. Safe call of 'count' is used inside 'handleFilesCorrect' function, also it returns zero if 'arr' is null.

See also

DEREF_OF_NULL.RET.USER

Situation Severity Reliability Supported languages Enabled by default
SuppressedNormalUnknownJava KOTLIN GONo

This checker finds situations where a pointer returned by a user-written procedure that returns NULL on some of the execution paths, is dereferenced without being checked for NULL value.

Example (C/C++)

 #define USE_PREFIX 1
 #define MAX_SIZE 1024
 
 char* buf[MAX_SIZE];
 
 char* get_login(const char* url, int flag) {
   if(flag==USE_PREFIX && url[0]!='%' && url[1]!='%')
     return NULL;

   return fill_from_bd(buf, MAX_SIZE);
 }

 void use(const char* url) {
   char* login = get_login(url, USE_PREFIX);
   int len = strlen(login);
   //...
 }

The 'DEREF_OF_NULL.RET.USER.PROC' subtype specifies that DEREF_OF_NULL.RET.USER happens inside a user-written procedure called from the code that causes the problem. In other words, the problem is caused by incorrect (unsafe) invocation of a procedure.

Example (Kotlin)

data class Wrapper(val value: Int)

class Helper(val wr: Wrapper?) {
    fun getMaybeNull() = wr?.value
}

fun example(h: Helper): Int {
    val num = h.getMaybeNull()
    return num!!.times(3)
}

fun possibleFix(h: Helper): Int? {
    val num = h.getMaybeNull()
    return num?.times(3)
}

fun deref(n: Int?) = n!!.times(3)

fun exampleProc(h: Helper): Int {
    val num = h.getMaybeNull()
    return deref(num)
}

fun derefCorrect(n: Int?) = n?.times(3)

fun possibleFixProc(h: Helper): Int? {
    val num = h.getMaybeNull()
    return derefCorrect(num)
}

Function 'example' illustrates the 'DEREF_OF_NULL.RET.USER' defect: 'num' may be null after 'getMaybeNull' call and it is dereferenced by call of 'times' function. Function 'possibleFix' illustrates a possible fix: use safe call of 'times' function.

Function 'exampleProc' illustrates the 'DEREF_OF_NULL.RET.USER.PROC' defect: 'num' may be null after 'getMaybeNull' call and it is dereferenced by call of user defined function 'deref'. Function 'possibleFixProc' illustrates a possible fix: use safe implementation 'derefCorrect'. Safe call of 'times' is used inside 'derefCorrect' function.

See also

DEREF_AFTER_NULL

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalHighC/C++ Java KOTLIN C# GOYes

This checker finds situations where first, a pointer is compared to NULL (which indicates that it could have a NULL value), and then it is dereferenced (unconditionally).

A subtype DEREF_AFTER_NULL.LOOP is emitted when the conditional expression comparing the pointer to NULL is part of a loop.

A (suppressed) .MACRO subtype of this warning is emitted if it is suspected that the warning is a false positive, caused by the conditional expressions being implemented within a macros. . Such checks can be too general and not always reflect possible value range of index variables.

Example (C/C++)

int test(char* str1, char* str2, int len) {
 if(!str1) {
   len = 0; 
 } else {
   len = strlen(str1);
 }
 return strcmp(str1, str2);
}

If str1 can be NULL, so that the conditional isn't trivial, then call of strcmp will lead to a null pointer dereference.

Example (Kotlin)

data class Client(val name: String, val age: Int)

fun example(arg: Client?) {
    val age = arg?.age
    println("Client '${arg!!.name}' is $age years old")
}

fun possibleFix(arg: Client?) {
    val age = arg?.age
    age?.let{ println("Client '${arg.name}' is $age years old") }
}

Function 'example' illustrates the defect: 'age' is got from 'arg' with null check, but 'name' is got avoiding null check. Function 'possibleFix' illustrates a possible fix. Note that Kotlin compiler knows that 'arg' is not null into 'let' code block.

False positives

This warning can cause false positives if the conditional expression has a side effect of terminating the program, but that wasn't noticed by the tool. For example:

 if(!str1) {
   my_exit();
 }
 return strcmp(str1, str2);

If instead of my_exit(), a standard exit(int) is called, no false warnings will be emitted. The same holds if my_exit() transparently calls exit(int) or one of the other functions annotated as terminating.

See also

DEREF_AFTER_NULL.EX

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++ Java KOTLIN GOYes

This checker is a version of the DEREF_AFTER_NULL with path sensitivity. Unlike DEREF_AFTER_NULL, it gives warning when the variable after comparing with null can be dereferenced, and there is a combination of the input parameters, what may cause a error.

Example (Kotlin)

import java.text.DateFormat
import java.util.*

fun example(date: String?): Date {
    date?.let{ println("parsing: '$date'") }
    val df = DateFormat.getDateInstance(DateFormat.LONG, Locale.KOREA)
    return df.parse(date)
}

fun possibleFix(date: String): Date {
    println("parsing: '$date'")
    val df = DateFormat.getDateInstance(DateFormat.LONG, Locale.KOREA)
    return df.parse(date) // svace: not_emitted DEREF_AFTER_NULL*
}

Function 'example' illustrates the defect: 'date' may be null according to safe call of 'let' block but it has been dereferenced onwards by passing as first parameter into 'parse' method. Function 'possibleFix' illustrates a possible fix: change function contract. First argument of 'possibleFix' function is non-nullable.

NULL_AFTER_DEREF

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++ Java KOTLIN C#Yes

The checker NULL_AFTER_DEREF finds situations where first, a pointer is dereferenced, and then it is compared to null (which indicates that it could have a NULL value).

A (suppressed) .MACRO subtype of this warning is emitted if it is suspected that the warning is a false positive, caused by the conditional expressions being implemented within a macros. Such checks can be too general and not always reflect possible value range of index variables.

Example (C/C++)

 struct bank {
   char* name;
   char* pool;
 };

 void test(struct bank* c, char* name) {
   strcpy(name, "<Global>");
 
   if (name)
     c->name = pstrdup(c->pool, name);
 }

If name can be NULL, so that the conditional isn't trivial, then call of strcpy will lead to a null pointer dereference.

Example (Kotlin)

import java.text.DateFormat
import java.util.Date
import java.util.Locale

fun example(date: String?): Boolean {
    val df = DateFormat.getDateInstance(DateFormat.LONG, Locale.KOREA)
    val ret = df.parse(date)
    date?.let{ println("'$date' has been parsed") } // svace: emitted NULL_AFTER_DEREF
    return ret.after(Date(2020, 12, 10))
}

fun possibleFix(date: String?): Boolean {
    val ret = date?.let {
        val df = DateFormat.getDateInstance(DateFormat.LONG, Locale.KOREA)
        df.parse(date).also { println("'$date' has been parsed") }
    }
    return ret?.after(Date(2020, 12, 10)) ?: false
}

Function 'example' illustrates the defect: 'date' may be null according to safe call of 'let' block but it has been dereferenced earlier by passing as first parameter into 'parse' method. Function 'possibleFix' illustrates a possible fix: wrap more code into 'let' block.

Notes

In some cases, the dereference indicated in the warning points to a function that returns the pointer. Such warnings mean that the function that produced the pointer unconditionally dereferences it, and so the returned pointer can't be NULL. In some cases, the code that checks the returned value for quality to NULL is protective or follows the specification that allows NULL value as possible behavior. In other cases, presence of the check indicates an incorrect assumption about the function.

See also

NULL_AFTER_DEREF.RET

Situation Severity Reliability Supported languages Enabled by default
CodingStyleMinorUnknownC/C++ JavaNo

The checker is like NULL_AFTER_DEREF, but it finds situations where pointer was dereferenced in a function and then returned. If the caller of that function still compares the returned value to NULL, they believe that it's possible for the returned value to be NULL, while it's actually not.

Example

 char* get_buf(void) {
   char* buf = (char*)malloc(100); 
   buf[0] = 'q';
   return buf;
 }
 
 void foo(void) {
   char* res = get_buf();
   if(res) // NULL_AFTER_DEREF.RET: 'res' can't be NULL
     res[1] = 'w';
 }

NULL_AFTER_DEREF.SHIFT

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++No

This checker is similar to NULL_AFTER_DEREF, but it finds situations where a pointer was first dereferenced and then its value was shifted. Svace emits a warning if the result of the shift operation can't be null but compared with null so that such comparison is redundant.

Example

 int bar(int* p) {
   p[0]++;//dereference of p 
   ++p;//shifting of p, the result is written to 'p'
   if(p) { //here p can not be null.
     p[1] = 0;
   }
 }

COMPARE_LOCAL_ADDR

Situation Severity Reliability Supported languages Enabled by default
QualityMinorAverageC/C++Yes

Since address of a local variable can't be null comparing it with null value is redundant.

Example

 int foo() {
   int x = 0;
   if(&x) //COMPARE_LOCAL_ADDR, maybe it should be if(x). 
     return 0;
   return 1;

Tainted input

Tainted input checkers find situations where a value obtained from external sources (network, files, environment variables) is used in an operation sensitive to incorrect or malicious parameters. The externally controlled value is called tainted, the location where tainted value is obtained is called source, and the location where tainted value is dangerously used is called sink. Checkers in this group consider tainted values of integer or C string types. TAINTED_INT.LOOP considers loop bounds as sinks.

Sources for TAINTED_INT:

 int getch(void);
 int _getch(void);
 int getchar(void);
 
 int atoi(const char* arg);
 long atol(const char* arg);
 long long atoll(const char* arg);
 long strtol(const char *restrict nptr, char **restrict endptr, int base);
 long long strtoll(const char *restrict nptr, char **restrict endptr, int base);
 unsigned long strtoul(const char *restrict nptr, char **restrict endptr, int base);
 unsigned long long strtoull(const char *restrict nptr, char **restrict endptr, int base);
 
 elements of tainted integer arrays

Sinks for TAINTED_INT:

 char *fgets(char *s, int num, FILE *stream);
 void* memset(void * ptr, int value, size_t num);
 ssize_t pwrite(int d, const void *buf, size_t nbytes, off_t offset);
 ssize_t write(int d, const void *buf, size_t nbytes);
 
 void *calloc(size_t num, size_t size);
 void *malloc(size_t size);
 void *xmalloc(unsigned long size);
 void *realloc(void *ptr, size_t size);
 void *xrealloc (void *ptr, size_t size);

Sources for TAINTED_PTR:

 ssize_t recv(int s, void *buf, size_t len, int flags);
 ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
 char *fgets(char *s, int num, FILE *stream);
 size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
 char *gets(char *s);
 ssize_t getline(char **lineptr, size_t *n, FILE *stream);
 char *getenv(const char* key);
 ssize_t read(int d, void *buf, size_t nbytes);
 
 scanf(...)

Sinks for TAINTED_PTR:

 FILE *fopen(const char *filename, const char *mode);
 FILE *freopen(const char *filename, const char *mode, FILE *stream);
 FILE *popen(const char *command, const char *mode);
 char* strcat(char *s, const char * append);
 char* strcpy(char *dst, const char *src);
 char* stpcpy(char *dst, const char *src);

Format string sinks:

 void err(int eval, const char *fmt, ...);
 void verr(int eval, const char *fmt, va_list args);
 void errx(int eval, const char *fmt, ...);
 void verrx(int eval, const char *fmt, va_list args);
 void warn(const char *fmt, ...) ;
 void vwarn(const char *fmt, va_list args);
 void warnx(const char *fmt, ...);
 void vwarnx(const char *fmt, va_list args);
 void error(int status, int errnum, const char *fmt, ...);
 int fprintf(FILE *stream, const char *format, ...);
 int fscanf(FILE *stream, const char *format, ...);
 int printf(const char *format, ...);
 int scanf(const char *format, ...);
 int sprintf(char *s, const char *format, ...) ;
 int snprintf(char *str, size_t size, const char *format, ...);
 int asprintf(char **ret, const char *format, ...);
 int sscanf(const char *s, const char *format, ...);
 int vscanf(const char *format, va_list ap);
 int vsscanf(const char *str, const char *format, va_list ap);
 int vfscanf(FILE *stream, const char *format, va_list ap);
 int vfprintf(FILE *stream, const char *format, va_list ap);
 int vprintf(const char *format, va_list ap);
 int vsprintf(char *s, const char *format, va_list ap);
 int vsnprintf(char *str, size_t size, const char *format, va_list ap);
 int vasprintf(char **ret, const char *format, va_list ap);
 void setproctitle(const char *fmt, ...);
 void syslog(int priority, const char *message, ...);
 void Tcl_Panic(const char* format, ...);
 void panic(const char* format, ...)

TAINTED_INT

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++ Java GOYes

The checker TAINTED_INT finds situations where an integer value received from external source (from a file or from the network; such value is called tainted value) is used in an operation where uncontrolled value may cause problems, such as allocation of memory of given size, or reading the given number of bytes from a file.

There is a .MIGHT variant of this warning (TAINTED_INT.MIGHT).

This warning has the following subtypes:

Example

 size_t size;
 char* res;

 void test() {
   char* env = getenv("QQQ");
   size = strtoul(env, NULL, 10);
 
   // allocating a buffer of unbounded number of bytes
   res = (char*)malloc(size);
 }

TAINTED_INT.CTYPE

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++Yes

A subtype of TAINTED_INT, where a tainted value is used in character type functions from header <ctype.h> (isdigit, isspace, etc.). ISO C requires that ctype functions work for unsigned char values and for EOF. Other values may lead to undefined behavior, but many library implementations also support negative signed char and some other values. This warning is suppressed if tainted integer is known to have values only in interval [-128;255].

Example

 char ch = '0';
 int val;
 
 void int_type() { 
   scanf("%d", &val);
   if(isdigit(val))  // here the program may crash; TAINTED_INT.CTYPE is emitted
     ch = (char)val;
 }

TAINTED_INT.LOOP

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalHighC/C++ JavaYes

A subtype of TAINTED_INT, where the tainted value is used as a bound in a loop, and thus may cause the program to hang.

Example

 size_t size;
 char* res;
 
 void test() {
   int i;
   char* env = getenv("QQQ");
   size = strtoul(env, NULL, 10);
 
   for(i=0; i<size; i++) {
     ...
   }
 } 

TAINTED_ARRAY_INDEX

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++ Java KOTLIN GOYes

The checker TAINTED_ARRAY_INDEX finds situations where an integer value received from external source (from a file or from the network) is used as an index in accessing an array, without ensuring that it's within bounds. This warning is a subtype of TAINTED_INT.

There is a .MIGHT variant of this warning (TAINTED_ARRAY_INDEX.MIGHT).

Example

 void array_index() {
   int buf[256];
   int index = getchar();

   if(index<256) {	
     // index may still be negative!
     buf[index]=7;
   }
 }

TAINTED_ARRAY_INDEX.LOOP

Situation Severity Reliability Supported languages Enabled by default
QualityMajorVeryLowC/C++ JavaNo

Kind of TAINTED_ARRAY_INDEX where array index depends on a tainted value and is used inside of a loop.

Example

  void simple() {
    char c;
    char tmp[32];

    while ( (c = getchar()) != (char) EOF) {
      tmp[c] = 0; //emitted TAINTED_ARRAY_INDEX.LOOP
    }
  }

TAINTED_INT.PTR

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalHighC/C++ JavaYes

This checker is very similar to TAINTED_ARRAY_INDEX, except that it finds situations where array access with tainted index value happens through a pointer (TAINTED_ARRAY_INDEX is emitted only when the array is identified explicitly by name).

There is a .MIGHT variant of this warning (TAINTED_INT.PTR.MIGHT).

Example

 void set_base(char* base) {  // here 'base' an unknown pointer that probably points to an array.
   char* env = getenv("QQQ");
   size_t size = strtoul(env, NULL, 10);
   base[size] = '\0'; // accessing an array through pointer 'base' by tainted index 'size'
 }

TAINTED_PTR

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalVeryHighC/C++ Java GOYes

The checker TAINTED_PTR finds situations where a string received from external source (from a file or from the network) is used in an operation where uncontrolled string (or unbounded size of the string) may cause problems, such as copying to a fixed-size array.

There is a .MIGHT variant of this warning (TAINTED_PTR.MIGHT).

Example

 char* env;
 char buf[100];
  
 void test() {
   env = getenv ("VAR3"); 
 
   // copying a string of unbounded size to a fixed-size buffer
   strcpy(buf, env);
 }

TAINTED.SPRINTF

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalUnknownC/C++Yes

This checker finds uses of library function sprintf() that may overflow the destination buffer, because some of the values (integer values or strings) printed according to a constant format string are tainted and unchecked.

Example 1

 char buf[100];
 char dst[16];

 void test() { 
   fgets(buf, 50, stdin);
   sprintf(dst, "* %s\n", buf);
 }

Example 2

 size_t size;
 char dst[5];
 
 void test() {
   char* env = getenv("QQQ");
   size = strtoul(env, NULL, 10);
 
   sprintf(dst, "%d", size);
 }

TAINTED_PTR.FORMAT_STRING

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalHighC/C++ JavaYes

The checker TAINTED_PTR.FORMAT_STRING finds situations where a string received from external source (from a file or from the network) is used as a format string parameter in functions of printf() family. This vulnerability may be used in a format string attack.

Example

 void fmt_str(int s, char* buf, int len, int flags) {
   recv(s, buf, len, flags);
   printf(buf);
 }

Buffer overflow

STATIC_OVERFLOW

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalLowC/C++ Java GOYes

The checker STATIC_OVERFLOW finds situations where a fixed-size array is accessed at a constant index outside its range.

Example

 void buf_overflow() {
   char buf[1024];
   buf[1024] = 0;
 }

DYNAMIC_OVERFLOW

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalHighC/C++ JavaYes

The checker DYNAMIC_OVERFLOW finds situations where a dynamic array is accessed at a constant index outside its range.

Example

 void buf_overflow() {
   char *buf = (char *)malloc(1024);
   buf[1024] = 0;
   free(buf);
 }

STATIC_OVERFLOW.LOCAL

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalLowC/C++ JavaYes

This checker finds buffer overflow situations where a buffer is accessed (with potential overflow) in the same procedure where it's locally defined.

Example

 void access_buf(int index) {
   int buf[10];
   buf[index] = 7;
 }
 
 void run() {
   int i;
   if(i>=10)
     access_buf(i);
 }

Here, the situation is detected interprocedurally (the condition that index is outside bounds is specified outside function access_buf). Warning of this type is emitted, because buffer access operation is in the same procedure as definition of the buffer.

See also

STATIC_OVERFLOW.PROC

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalVeryLowC/C++ JavaNo

This checker finds buffer overflow situations where a buffer is passed into another procedure before being accessed (with potential overflow).

Example

 void access_buf(int* buf) {
   buf[10] = 0;
 }
 
 void run() {
   int buf[10];
   access_buf(buf);
 }

Since buf is only 10 elements long, the access operation in procedure access_buf overflows the buffer. This situation is detected interprocedurally, since the size of the buffer is not available inside procedure access_buf.

See also

STATIC_OVERFLOW.SPRINTF

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalUnknownC/C++Yes

This checker finds situation where a function from sprintf() family is used to write to a buffer of known size, but the constant format string and possible values of the arguments are such that the buffer could overflow as a result of the call.

Example

 void static_overflow(char* val) {
   char buf[6];
   sprintf(buf,"%d!", val);
 }

The checker will emit a warning for this example, unless val is known to be in the interval [-999,9999] (up to 4 characters for the value, one for symbol '!' and one for NULL terminator at the end of the string, total of up to 6 characters).

STATIC_OVERFLOW.SCANF

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalVeryHighC/C++Yes

This checker finds situation where a function from scanf() family is used to read data into a buffer of known size, but the constant format string and possible values of the source of the data are such that the buffer could overflow as a result of the call.

Example

 void static_overflow(FILE* f) {
   char buf[50];
   fscanf(f, "%s", buf); // buf can overflow
 }

Since the number of bytes read from the stream f is not restricted, the buffer can overflow. One way to fix this defect is to specify the maximum number of characters to be read explicitly:

 void avoid_overflow(FILE* f) {
   char buf[50];
   fscanf(f, "%49s", buf); // buf can't overflow: bounds specified in format string
 }

BUFFER_OVERFLOW.VALUES

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++ JavaNo

The checker finds situations where a fixed-size array is accessed with an index outside its range. It is similar to STATIC_OVERFLOW but analyzes acesses with non-constant indexes.

Example

 static int buf[128];

 void foo(int index){
   if(index > 255) {
     buf[index] = 0;
   }
 }

CHECK_AFTER_OVERFLOW

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++ JavaYes

The checker CHECK_AFTER_OVERFLOW finds situations where first, a buffer is accessed with a certain index, and then this index is compared to some value that indicates that the index may lie outside the buffer's range.

Example

 char buf[256];

 int test(int i) { 
   buf[i] = 0;

   if(i!=256)
     return 1;
   return 0;
 }

In this example, the check at the end shows that i is expected to sometimes have a value of 256, in which case the buffer access above will be out of bounds.

A (suppressed) .MACRO subtype of this warning is emitted if it is suspected that the warning is a false positive, caused by the conditional expressions being implemented within a macros. Such checks can be too general and not always reflect possible value range of index variables.

OVERFLOW_AFTER_CHECK

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++ JavaYes

The checker OVERFLOW_AFTER_CHECK finds situations where first, a variable is compared to some value, indicating what the possible values of the variable are, and then it's used to access a buffer in such a way that one of the possible values indicated by the check lies out of bounds.

Example

 char buf[256];

 void overflow(int i) {
   if(i>255)
     printf("i>255");
 
   buf[i] = 0;
 }

OVERFLOW_UNDER_CHECK

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++ Java GOYes

Issues of this type are detected when the value of an index used to access a buffer is checked with a bound that is less strict than necessary. A bound on an index value can be used to ensure the absence of buffer overflows due to index value being too high or too low, but if the bound is itself too high or too low, a buffer overflow can still occur. For example, if a buffer has 10 elements, index values up to 9 are permitted, but checking that the index is less than 20 allows values between 10 and 19 that would lead to buffer overflow.

Example

 int buf[10];

 if (i<20)
   buf[i] = 3; // possible buffer overflow

 if (i>=-1)
   buf[i] = 5; // possible buffer overflow

 for (i=0; i<100; ++i)
   buf[i] = 7; // possible buffer overflow

BUFFER_SIZE_MISMATCH

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++Yes

The checker BUFFER_SIZE_MISMATCH finds situations where a size parameter passed to "safe" versions of standard functions (such as strncpy or memset) is unsafe (out of local buffer bounds).

Example

 char dst[10];
 char src[11];

 void test() { 
   strncpy(dst, src, sizeof(src));
 }

The last parameter for strncpy() should've been sizeof(dst)-1.

BUFFER_SIZE_MISMATCH.STRICT

Situation Severity Reliability Supported languages Enabled by default
QualityNormalAverageC/C++Yes

The checker BUFFER_SIZE_MISMATCH.STRICT finds situations where a size parameter passed to "safe" versions of standard functions (such as memset_s, sprintf_s) is not constant and may be out of bounds.

Example

 char dst[10];

 void test_bad(int size, char* src) { 
   memcpy_s(dst, size, src, strlen(src));
 }

 void test_good(char* src) { 
   memcpy_s(dst, 10, src, strlen(src));
 }

DYNAMIC_SIZE_MISMATCH

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++ JavaYes

The checker DYNAMIC_SIZE_MISMATCH finds situations where a size parameter passed to "safe" versions of standard functions (such as strncpy or memcpy) is unsafe (out of dynamic buffer bounds).

Example

 char *dst;
 char src[11];

 void test() {
   dst = (char *)malloc(10); 
   strncpy(dst, src, sizeof(src));
 }

The last parameter for strncpy() should've been sizeof(dst)-1.

ALLOC_SIZE_MISMATCH

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++Yes

This checker reports warnings for instances of pointer assigned memory allocations where the pointer's target type is larger than the block allocated.

Example

 struct Person {
   int age;
   char name[20];
 };

 struct Person *foo(void) {
   struct Person *ptr;
   ptr = (Person *)malloc(sizeof(ptr));  // mismatched allocation size
   return ptr;
 }

In this example, the allocation is too small for the pointer's target type – sizeof(*ptr) was probably intended.

Situation Severity Reliability Supported languages Enabled by default
QualityMajorVeryHighC/C++Yes

This checker finds situations where function 'readlink' (from libc) is used incorrectly. Function 'readlink' returns -1 on error, or the number of bytes written in the buffer, but doesn't write terminating NULL, so that it may return value equal to buffer size.

Example

 char buf[128];

 void overflow() {
   int len = readlink("/mnt/modules/pass1", buf, sizeof(buf));
   if(len != -1) {
     //len may be = sizeof(buf) = 128
     buf[len] = 0; // emitted READLINK_OVERFLOW
   }
 }

NONTERMINATED_STRING

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalHighC/C++Yes

The checker NONTERMINATED_STRING finds situations where "safe" versions of standard functions working with C strings enable creation of nonterminated strings as a result.

Example

 char dst[10];
 char src[15];
 
 void cp_str() {
   strncpy(dst, src, sizeof(dst));
 }

Even though buffer overflow won't occur directly in this call, it may create a non-terminated string, which may lead to buffer overflow later, when the string is accessed again. For example, if src is a 10-character string, the call will copy all 10 characters in dst, but there is no space left for a null terminator.

See also

TAINTED.NONTERMINATED_STRING

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++Yes

This checker finds situations where "safe" versions of standard functions working with C strings enable creation of non-nullterminated strings as a result of using length parameter coming from untrusted source.

 char dst[10];
 
 void cp_str() {
   char* src = getenv("qqq");
   strncpy(dst, src, sizeof(dst));
 }

NONTERMINATED_STRING.USE

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalUnknownC/C++No

This checker is similar to NONTERMINATED_STRING, but finds situations where a non-terminated string is used, as opposed to where it is created.

Example

 char buf[8];
 
 void cp_str(char* src, char* tgt) {
   strncpy(buf, src, 8);
   strcpy(tgt, buf); // NONTERMINATED_STRING.USE: buf could be a non-terminated string
 }

NONTERMINATED_STRING.STRICT

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++No

This checker is similar to NONTERMINATED_STRING, but doesn't assume that destination memory is zero-filled. It is reported when copying a smaller string into a bigger buffer without adding a null terminator. This can lead to unintended addition of a suffix to the copied string or nonterminated string if the destination buffer wasn't null-terminated.

STRING_OVERFLOW

Situation Severity Reliability Supported languages Enabled by default
QualityMinorVeryHighC/C++Yes

This checker finds situations where a call to a string copying function can lead to a buffer overflow if the source string is larger than the destination buffer.

Example

 char buf[100];

 void test1(char* param) {
   strcpy(buf, param);
 }

OVERFLOW_UNDER_CHECK.LEN

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++No

The checker finds situations of potential overflow where string length is used to check possible size of buffer.

Example

void example(char* q) {
    int len = strlen(q);

    if(len>0) {
        struct S*s = (struct S*)q;
        s->x = 1;//potential overflow if len < sizeof(struct S).
    }
}

Memory management

FREE_NONHEAP_MEMORY

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++Yes

This checker finds situation where a pointer to non-heap memory could be passed to a memory deallocation function.

Example

 int buf[5];
 int* ptr;

 void test(int cond) { 
   if(cond)
     ptr = (int*) malloc(10);
   else
     ptr = buf;
   ...
   free(ptr); // 'ptr' could reference non-heap array 'buf'
 }

FREE_OF_ARITHM

Situation Severity Reliability Supported languages Enabled by default
QualityMinorVeryLowC/C++Yes

This checker finds situation where a pointer passed to a memory deallocation function was obtained as a result of an arithmetic operation. Though sometimes the correct address of the beginning of a memory allocation block could be reconstructed using arithmetic operations, this is potentially a serious problem.

Example

 void foo(int* ptr) {
   int* start = ptr-30;
   free(start);
 }

ALLOC_ARITHM

Situation Severity Reliability Supported languages Enabled by default
QualityMinorVeryLowC/C++No

It emits warnings for arithmetic operation on the results of heap allocation functions. This might be a common typo when a closing brace is mistakenly placed before a part of the arithmetic expression for allocation size calculation.

Example

 char *mystrcpy(char *str) {
  char *ret = malloc(strlen(str)) + 1;  // Typo
  for (; *str;) *ret++ = *str++;
  char *copy = ret;
  *copy = 0;
  return ret;
 } 

Suggested code

char *mystrcpy(char *str) {

char *ret = malloc(strlen(str) + 1); Correct size allocation for the whole string and zero terminator for (; *str;) *ret++ = *str++; char *copy = ret; *copy = 0; return ret;

}

FREE_OF_NULL

Situation Severity Reliability Supported languages Enabled by default
QualityMinorAverageC/C++Yes

This checker finds situations where a NULL pointer is passed to the library function free().

Example 1

 void test(int z, char* x) {
   if(z==7) {
     x = NULL;
 
     free(x);
   }
 }

Example 2

 void test(int x, char* z) {
   if(z==NULL) {
     x = 7;
 
     free(z);
   }
 }

See also

DEREF_AFTER_FREE

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++Yes

This checker finds situations where a memory location is accessed through a pointer that has just been deallocated.

Example

 void test(char* pval, char x) {
   free(pval);
   x = *pval;
 }

See also

USE_AFTER_FREE

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++Yes

This checker finds situations where the value of a pointer to a memory location that has been deallocated, is accessed.

Example

 void after_free(char* pval, char* pval2) {
   free(pval);
   pval2 = pval + 2;
 }

Example

 char* foo(char* x) {
   free(x);
   return x;
 }

See also

USE_AFTER_FREE.REALLOC

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalLowC/C++Yes

Subtype of USE_AFTER_FREE for situations where a pointer is passed to the realloc function that invalidates it but the original pointer value is used afterwards.

Example

  void boo() {
    int *newp = (int *) realloc (p, SIZE);//'p' is released
    p[0] = 1;//use of 'p'
    free(newp);
  }

PASSED_TO_PROC_AFTER_FREE.EX

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++Yes

This checker finds situations where a pointer referencing deallocated memory is passed to a function.

Example

 void foo(char* p);

 void run(char* p) {
   free(p);
   foo(p);
 }

Here, pointer p passed to a call of foo references memory deallocated by function free. One way to fix this defect is to set the deallocated pointer to NULL:

 free(p);
 p = NULL;
 foo(p); // no warning

Example

 struct proc {
   char* mem;
   int a;
 };

 void foo(struct proc* p);

 void run(struct proc* p) {
   free(p->mem);
   foo(p); // p->mem is referenced by p
 }

See also

DOUBLE_FREE.EX

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++Yes

This checker finds situations where a pointer referencing deallocated memory is deallocated again.

Example

 char* foo(char* x) {
   free(x);
   free(x);
 }

DANGLING_POINTER.STRICT

Situation Severity Reliability Supported languages Enabled by default
QualityMinorHighC/C++No

This checker is designed to detect dangling pointers and resources, i.e. such pointers and resources that can be available from the caller context after they have been freed or released inside of the callee.

Example

int naive_pop(struct list *l)
{
  if (l == NULL) {
    return 0;
  }
  int *p = l->ptr;
  int ret = *p;
  free(p); // No removing of the freed pointer from the list, it remains there as a
           // dangling pointer that could crash the program on its dereference
  return ret;
}

Example

 typedef struct _St {
   char *p1;
   char *p2;
 } St;

 void ex(St *s) {
   if (cond1()) {
     free(s->p1);
     s->p1 = NULL; // Correct: the deallocated pointer is cleared
     return;
   }

   if (cond2()) {
     free(s->p1);  // Potential defect: the deallocated pointer may be used outside of the function
     return;
   }
 }

DANGLING_POINTER.STAT

Situation Severity Reliability Supported languages Enabled by default
QualityNormalHighC/C++Yes

Statistical version of DANGLING_POINTER. Svace emits this subtype when for some cases externally accessible memory pointing to it is reassigned and for others it isn't.

INCORRECT_STRLEN

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++Yes

This checker detects possible mismatch when using function 'strlen' to determine the size of a newly allocated buffer based on the length of an existing string.

Example

 char* alloc_same_plus_1(char* str) {
   char* res = (char*)malloc(strlen(str+1)); // svace emits INCORRECT_STRLEN
   res[0] = '\0';
   return res;
 }

strlen(str+1) return value that is less than strlen(str). Programmer probably wanted to write (strlen(str) + 1) to allocate 1 byte more than the length of 'str'; also, 'str+1' skips NULL terminator if 'str' was empty, leading to undefined behavior.

MEMORY_LEAK

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++Yes

This checker detects memory leak situations, where memory was allocated, and then all references to that memory were lost.

Example 1

 void mem_leak() {
   char* ptr1 = (char*)malloc(10);
   ptr1 = 0; // memory is leaked here
 }

Example 2

 void mem_leak() {
   char* str = strdup("hello");
   str = "qqq"; // memory allocated by function strdup is leaked here
 }

BUFFER_OVERLAP

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalLowC/C++Yes

This checker reports cases of using of the same source and destination buffers in function calls where it is prohibited such as memcpy.

HANDLE_LEAK

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++ Java KOTLIN C#Yes

This checker finds situations where a file descriptor, file handle or a socket descriptor are lost, because local variables that held their value went out of scope or were re-assigned.

Example (C/C++)

 void func1() {
   FILE* f = fopen("qqq.c", "w");
 }

 void func2() {
   FILE* f = fopen("qqq.c", "w");
   f = 0;
 }

In some cases it might be possible for the programmer to predict the value of a descriptor returned by a function that allocates it. For example, after closing standard descriptor 1, the next allocated descriptor will have value 1. In such cases, even if the returned value is not recorded, the predicted value can still be used to deallocate resources. For these situations, Svace emits warnings of subtype HANDLE_LEAK.STRICT.

Example (Kotlin)

fun example(bytes: ByteArray) {
    val stream = File("data.txt").inputStream()
    stream.read(bytes)
}

fun possibleFix(bytes: ByteArray) {
    File("data.txt").inputStream().use { it.read(bytes) }
}

Function 'example' illustrates the defect: file input stream was created for 'data.txt' but it wasn't closed properly. Function 'possibleFix' illustrates a possible fix: call 'use' function which executes the given block function on this resource and then closes it down correctly whether an exception is thrown or not.

HANDLE_LEAK.EXCEPTION

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++ Java KOTLIN C#Yes

This checker finds situations where a file descriptor, file handle or a socket descriptor are lost because of exception, which went out of scope.

Example (Kotlin)

import java.io.*
import java.lang.IllegalStateException
import java.util.zip.*

fun example(f: File, com: String) {
    try {
        val zip = ZipOutputStream(FileOutputStream(f))
        zip.putNextEntry(ZipEntry("putNextEntry may throw exception"))
        zip.close()
    } catch (ex: Exception) {
        throw IllegalStateException(ex.message)
    }
}

fun possibleFix(f: File, com: String) {
    ZipOutputStream(FileOutputStream(f)).use { zip ->
        zip.putNextEntry(ZipEntry("putNextEntry may throw exception"))
    }
}

Function 'example' illustrates the defect: file output stream was created for 'f' but it will not be closed if 'putNextEntry' call raises an exception. Function 'possibleFix' illustrates a possible fix: call 'use' function which executes the given block function on this resource and then closes it down correctly whether an exception is thrown or not.

DOUBLE_CLOSE

Situation Severity Reliability Supported languages Enabled by default
QualityNormalAverageC/C++ Java GOYes

This checker finds situations where a closed file descriptor is closed again.

Example

 void foo() {
   FILE *f = fopen("bar", "w");
   /* ... */
   fclose(f);
   /* ... */
   if (error()) {
     fclose(f);
   }
 }

Example

 void dup_to_2(int fd) {
   close(2);//now 2 is available
   dup(fd); //2 will be used
 }

Infinite loop

This checker find situations where number of loop iteration may be infinite because of integer overflow.

INFINITE_LOOP.INT_OVERFLOW

Situation Severity Reliability Supported languages Enabled by default
QualityMajorLowC/C++ Java GONo

Example 1

void example1() {
    unsigned char i;

    for(i=0;i<250;i+=10) {//possible integer overflow, after i = 240
        bar();
    }
}

Example 2

void example2(unsigned len) {
     int i = 0;

    while (len > 0) {
        len -= 8; //overflow if len % 9 != 0
    }

INFINITE_LOOP.STRING

Situation Severity Reliability Supported languages Enabled by default
QualityMajorVeryLowC/C++ Java GONo

This checker finds situations where number of loop iteration may be more than it was intended. The loop is depended from value of string.

Example

void func(char * pos) {
    while (*pos != ' ') {
        pos++;
    }
}

Integer overflow

TAINTED.INT_OVERFLOW

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++ JavaNo

The checker finds situations where value from external source is used in arithmetic operation without checking its range. It potentially may lead to integer overflow.

Example

int add_to_str(const char *str) {
    int index = atoi(str);
    int res = index + 500; //potential integer overflow
    return res;
}

TAINTED.INT_OVERFLOW.TRUNC

Situation Severity Reliability Supported languages Enabled by default
QualityNormalAverageC/C++ Java GONo

The checker finds situations where value from external source is passed to variable with smaller type size.

Example

    unsigned i;
    scanf("%3x", &i);
    unsigned short h = i; //potential loss of higher bits

INT_OVERFLOW.TRUNC.UNDER_BITMASK

Situation Severity Reliability Supported languages Enabled by default
QualityNormalAverageC/C++ Java GONo

The checker finds situations where potential integer overflow is possible for result of bit-manipulation operations.

Example

void foo(unsigned short a);

#define INVERT_BYTES_16(X)  (             ( ((X) & 0xFF00) >> 8 )         |   ( ((X) & 0x00FF) << 8 )     )

void bar(unsigned short b) {
    foo(INVERT_BYTES_16(b) + 1);
}

INT_OVERFLOW.LIB

Situation Severity Reliability Supported languages Enabled by default
QualityNormalAverageC/C++ Java GONo

The checker detects cases where the subtraction is performed on an unsigned value which can be 0 (or small enough), and, therefore the subtraction result may underflow, and it is passed to a function as its sensitive unsigned integer data argument.

Example

void example(char* dst, char* str) {
    size_t len = strlen(str);
    memcpy(dst, str, len - 
}

Secure errors

SENSITIVE_LEAK

Situation Severity Reliability Supported languages Enabled by default
QualityUndefinedLowC/C++ Java GONo

Checkers finds situatins where sensitive data may be occur to logs or be visible.

Example

char *password =  = getpass();
printf(password); 

HARDCODED_PASSWORD

Situation Severity Reliability Supported languages Enabled by default
QualityUndefinedLowC/C++ Java GONo

Checker finds situations where hardcoded password is passed to functions manipulating with passwords.

Example

var pass = []byte("0123456789abcdef0123456789abcdef")

func main() {
    block,_ := aes.NewCipher(pass) /using of hardcoded password
}

Concurrency

DEADLOCK

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalUnknownC/C++ Java C#Yes

This checker finds code that may result in two or more threads are waiting for each other, holding locks needed for the other to resume execution.

Example

 pthread_mutex_t *a, *b;

 void thread1() {
   pthread_mutex_lock(a);
   pthread_mutex_lock(b);
   ...
 }

 void thread2() {
   pthread_mutex_lock(b);
   pthread_mutex_lock(a);
   ...
 }

DOUBLE_LOCK

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++ JavaYes

The checker DOUBLE_LOCK finds situations where a lock is acquired twice in succession by the same thread (without getting released).

Example

 void proc(pthread_mutex_t* mut, int x) {
   pthread_mutex_lock(mut);
   if(x)
     pthread_mutex_unlock(mut);
 
   pthread_mutex_lock(mut);   // DOUBLE_LOCK: pthread_mutex_unlock() might not have been called
   ...
   pthread_mutex_unlock(mut);
 }

NO_UNLOCK

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++ JavaYes

This checker finds situations where a thread acquires a lock during function execution and leaves it locked on some paths to the exit from the function, but the function also unlocks it on some of the other paths.

Example

 void test(pthread_mutex_t* mut, int flag) {
   pthread_mutex_lock(mut);
   if(flag) {
     return; //mut isn't unlocked on this path
   }
   pthread_mutex_unlock(mut);
 }

LONG_TIME_IN_LOCK

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++Yes

This checker finds situations where a blocking function is called inside a critical section. As a result, all threads have to wait for the blocking function to return, not just the thread that called it.

Example

 int proc(pthread_mutex_t* mut, pthread_mutex_t* socket) {
   pthread_mutex_lock(mut);  // lock
   int res = accept(socket); // this function might take a lot of time
   pthread_mutex_unlock(mut);
   return res;
 }

LOCK_ON_STACK

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++Yes

This checker finds situations where a local variable allocated on stack is used as a synchronization primitive. Since each thread has its own stack such locks can't be used for inter-thread synchronization.

Simple example

 void foo() {
  pthread_mutex_t m;

  pthread_mutex_lock(&m); //locking stack variable
 }

More complex example

class AutoLock {
public:
    AutoLock(pthread_mutex_t *_m) {
        m = _m;
    }

    AutoLock() {}

    ~AutoLock() {
        pthread_mutex_unlock(m);
    }

    void lock() {
        pthread_mutex_lock(m);
    }
private:
    pthread_mutex_t *m;
};

pthread_mutex_t m_glob;//it should be used.

void bar() {
    AutoLock l;
    l.lock(); //Variable l is on stack. l.m is also on stack. 
}

RACE.NO_UMASK

Situation Severity Reliability Supported languages Enabled by default
QualityMinorVeryHighC/C++Yes

Warning of this type is emitted where a call to function 'mkstemp' is not preceded by a call to 'umask', which is necessary to restrict access rights to the newly created file to its creator.

See also

RACE.BAD_UMASK

Situation Severity Reliability Supported languages Enabled by default
QualityMinorVeryHighC/C++Yes

Even if function 'umask' was called before 'mkstemp', as checked by RACE.NO_UMASK, it's possible that access rights set by 'umask' are too permissive (for example, 777). This warning is emitted if that is the case.

See also

Signal handlers

SIGHANDLER.ASYNC_UNSAFE

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++No

This checker finds possible cases of using inconsistent data while executing asynchronous-unsafe functions from signal handlers. According to Section 7.14.1.1 of the C Rationale [ISO/IEC 2003]:

When a signal occurs, the normal flow of control of a program is interrupted. If a signal occurs that is being trapped by a signal handler, that handler is invoked. When it is finished, execution continues at the point at which the signal occurred. This arrangement can cause problems if the signal handler invokes a library function that was being executed at the time of the signal.

The warning is emitted if signal handler calls any asynchronous-unsafe function. It is based on the SIG30-C rule from the CERT Secure Coding Standard.

Example

 char* info;

 void handler(int signum) {
   free(info); // free is an asynchronous unsafe function,
               // so the warning will be emitted here.
   info = NULL;
 }
 
 int main(void) {
   signal(SIGINT, handler); // register 'handler' as a handler
   //...skipped
   return 0;
 }

SIGHANDLER.SELF

Situation Severity Reliability Supported languages Enabled by default
QualityMinorUnknownC/C++No

This checker finds a rare case of race condition where a handler tries to reinstall a signal handler from itself. On systems that deinstall signal handler after signal delivery (SysV and Windows behavior) another signal can happen before the reinstallation code is run. This will lead to default signal handler call. On systems where signal handlers need to be explicitly deinstalled (BSD and Linux behavior), reinstallation of same signal handler doesn't make sense.

The warning is emitted if a signal handler calls function 'signal' for re-registering same handler again. It is based on the SIG34-C rule from the CERT Secure Coding Standard.

Example

 void handler(int signum) {
   signal(signum, handler); // call to 'signal' from within 'handler' to register
                            // 'handler' again; the warning is emitted here
 }
 
 int main(void) {
   signal(SIGINT, handler); // register 'handler' as a handler
   //...skipped
   return 0;
 }

SIGHANDLER.ACCESS_SHARED

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++No

This checker detects race conditions that can be caused by accessing or modifying shared objects in signal handlers. The only way to guarantee that data is read in consistent state and remains in consistent state after modification is to read and write only variables of type volatile sig_atomic_t inside of signal handlers.

The warning is emitted if signal handler accesses or modifies global data with the type other than volatile sig_atomic_t. It is based on the SIG31-C rule from the CERT Secure Coding Standard.

Example

 volatile sig_atomic_t iflag = 0;
 int kflag = 0;

 void int_handler(int signum) {
   iflag = 2; // all ok, iflag is volatile sig_atomic_t
 }

 void kill_handler(int signum) {
   kflag = 3; // the warning is emitted: modifying shared object 'kflag' in a signal handler
 }
 
 int main(void) {
   signal(SIGINT, int_handler); // handler is registered
   signal(SIGKILL, kill_handler); // handler is registered
   //...skipped
   return 0;
 }

SIGHANDLER.LONGJUMP

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++No

This checker finds situations where a 'longjmp' function is called from a signal handler, which may cause inconsistent data use. Such calls can lead to problems similar to those discussed in SIGHANDLER.ASYNC_UNSAFE.

The warning is emitted if the signal handler function calls the 'longjump' function. It is based on a SIG32-C rule from the CERT Secure Coding Standard.

Example

 static jmp_buf env;

 void handler(int signum) {
   longjmp(env, 1); // call to 'longjump' from a signal handler
 }
 
 int main(void) {
   signal(SIGINT, handler); // handler is registered
   //...skipped
   return 0;
 }

SIGHANDLER.REC_RAISE

Situation Severity Reliability Supported languages Enabled by default
QualityMinorUnknownC/C++No

This checker finds situations where undefined behavior may result from calling function 'raise' from a signal handler. According to C99, Section 7.14.1.1 [ISO/IEC 9899:1999]:

If the signal occurs as the result of calling the abort or raise function, the signal handler shall not call the raise function.

The warning is emitted if function 'raise' is called from a signal handler, but only if a signal with that handler is explicitly raised using functions 'raise' or 'abort' somewhere in the program. It is based on the SIG33-C rule from the CERT Secure Coding Standard.

Example

 void log_msg(int signum) {
   //...skipped
 }

 void handler(int signum) {
   raise(SIGUSR1); // handler for SIGINT recusively calls 'raise'
 }
 
 int main(void) {
   signal(SIGUSR1, log_msg); // handler is registered
   signal(SIGINT, handler); // handler is registered
   //...skipped

   raise(SIGINT); // 'raise' is explicitly called for SIGINT
   //...other code
   return 0;
 }

SIGHANDLER.NO_ABORT

Situation Severity Reliability Supported languages Enabled by default
QualityMinorUnknownC/C++No

This checker detects cases of undefined behavior caused by returning control from certain signal handlers that should instead terminate the program. According to Section 7.14.1.1 of the C standard, returning from SIGSEGV, SIGILL, or SIGFPE signal handlers leads to undefined behavior:

If and when the function returns, if the value of sig is SIGFPE, SIGILL, SIGSEGV, or any other implementation-defined value corresponding to a computational exception, the behavior is undefined; otherwise, the program will resume execution at the point it was interrupted.

The warning is emitted if signal handler for SIGFPE, SIGILL or SIGSEGV can return without calling the 'abort' function. It is based on the SIG35-C rule from the CERT Secure Coding Standard.

Example

 volatile sig_atomic_t flag;

 void handler(int signum) {
   flag = 1; // no call of 'abort'
 }
 
 int main(void) {
   signal(SIGILL, handler); // handler is registered
   //...skipped
   return 0;
 }

C++ warnings

Those warnings are developed special for C++ code.

UNINIT.CTOR

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++Yes

This checker finds constructors (incl. copy constructor) that fail to initialize some of their class's fields.

Example

 class MyData {
 public:
   MyData();
   int kind;
   char ch;
   int sum;
 };

 MyData::MyData() : ch('q') {
   this->kind = 7; // warning: field 'sum' is not initialized
 }

Notes

Code detected by this checker doesn't necessarily lead to reading of uninitialized memory, since fields that were not initialized in the constructor might be initialized later or never accessed without additional initialization.

UNINIT.ASSIGN_OP

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++No

Finds implementations of 'operator=' that fail to initialize all class fields.

Example

 class MyData {
 public:
   MyData& operator=(const MyData& a);
   int kind;
   char ch;
 };

 MyData& MyData::operator=(const MyData& a) {
   this->kind = a.kind;
   return *this; // warning: field 'ch' wasn't initialized.
 }

UNINIT_HEAP.CCTOR

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++Yes

This checker finds classes in which the destructor explicitly deallocates memory using a pointer, but the copy constructor doesn't initialize this pointer or doesn't exist. Not handling such pointer in copy constructors may lead to either deallocation via an uninitialized pointer, or to double deallocation of the same memory.

Example

 class MyData {
   char* str;
   int size;
 public:
   MyData() {
     str = (char*)malloc(10);
     size = 10;
   }

   MyData(const MyData& a) {
     size = a.size; // 'str' is not handled
   }

   ~MyData() {
     free(str); // deallocate memory pointed to by 'str'
   }
 };

UNINIT_HEAP.ASSIGN_OP

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++Yes

This checker finds classes where the destructor deallocates memory using a pointer, but the assignment operator doesn't initialize this pointer or doesn't exist. This checker is similar to UNINIT_HEAP.CCTOR, but checks assignment operators instead of copy constructors.

HEAP_INCOMPATIBLE.FREE

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++Yes

Warnings of this type are emitted for situations where memory is deallocated in a way that is incompatible with how it was allocated. For example, usage of C functions malloc/free must not be mixed with C++ operators new/delete.

 char* buf = (char*)malloc(strlen(str) + 12);
 //...
 delete buf; // HEAP_INCOMPATIBLE.FREE is emitted here. The bug can be fixed 
             // by using function 'free' for deallocation instead of 'delete'.

See also

HEAP_INCOMPATIBLE.ARRAY

Situation Severity Reliability Supported languages Enabled by default
QualityMajorVeryHighC/C++Yes

A subtype of HEAP_INCOMPATIBLE.FREE. Detects situations where memory was allocated using array allocation operator 'new[]', but deallocated using operator 'delete' (instead of the correct 'delete[]'). Using incorrect deallocation method can lead to undefined behavior.

 char* buf = new char[SIZE_MAX];
 //...
 delete buf; // HEAP_INCOMPATIBLE.ARRAY warning is emitted here. The bug can be fixed by using delete[].

See also

HEAP_INCOMPATIBLE.CTOR

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++Yes

This checker finds classes with a constructor that allocates memory using a function (operator) that is incompatible with the function used by the destructor for deallocation. Examples of incompatible function pairs: new/free, malloc/delete, new[]/delete, new/delete[].

Example

 class C {
   int* buf;
 public:
   C() {
     buf = new int[10];
   }

   ~C() {
     free(buf);//here svace fires the warning.
   }
 };

See also

MEMORY_LEAK.CTOR

Situation Severity Reliability Supported languages Enabled by default
QualityNormalAverageC/C++Yes

This checker finds classes with a constructor that explicitly allocates memory, but which isn't deallocated in the destructor.

Example

 class C1 {
   int* buf;
 public:
   C1() { buf = new int[10]; }
   ~C1();
 };

 C1::~C1() { // warning: missing delete[] for buf
 }

DEAD_STRING_REF

Situation Severity Reliability Supported languages Enabled by default
QualityNormalHighC/C++Yes

This warning is emitted when an internal string buffer (returned by c_str()) of an STL string escapes its scope.

Example

 int func() {
   const char* p;
   {
     std::string s("Hello");
     p = s.c_str();
   } // scope of 's' ends, destructor is invoked
  
   // memory referenced by 'p' is no longer valid here
   return *p; // emit DEAD_STRING_REF
 }

ASSIGN_NO_CHECK_FOR_THIS

Situation Severity Reliability Supported languages Enabled by default
QualityMinorHighC/C++Yes

Finds implementations of 'operator=' that fail to check their argument for equality to 'this' (which is necessary to correctly handle statements such as 'x=x;').

Example

 class MyData {
 public:
   MyData& operator=(const MyData& a);
 private:
   int pkind;
 };

 MyData& MyData::operator=(const MyData& a) {
   this->pkind = a.pkind; // warning: 'a' wasn't checked for equality to 'this'
   return *this;
 }

The problem can be fixed as follows:

 MyData& MyData::operator=(const MyData& a) {
   if(&a == this)
     return *this;
   this->pkind = a.pkind; // no warning
   return *this;
 }

False positives

There are possible false positives if implicit checking is present in field copy operations.

ASSIGN_NO_REFERENCE_TO_THIS

Situation Severity Reliability Supported languages Enabled by default
QualityMinorUnknownC/C++No

Correctly written assignment operator (operator=) should return a reference to '*this', so that code like 'a = b = c;' is legal. This checker finds situations where the assignment operator doesn't have a return type or returns wrong value.

Example 1

 class MyData {
 public:
   void operator=(const MyData& a);
 private:
   int kind;
 };

 void MyData::operator=(const MyData& a) { 
   this->kind = a.kind; // return type is void, instead of MyData&
 }

Example 2

 class Base {
 public:
   Base& operator=(const Base& a);
 private:
   Base* ptr;
 };

 Base& Base::operator=(const Base& a) {
   return *this->ptr; // return type is correct, but 'operator=' 
                      // doesn't return reference to 'this'.
 }

Example 3

 class Base {
 public:
   Base& operator=(const Base& a);
 private:
   int ptr;
 };
 
 Base& Base::operator=(const Base& a) {
   this->ptr = a.ptr;
   return *this; // correct, no warning.
 }

STL_INCORRECT_ITERATOR

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++No

This checker finds situations where STL iterators are used incorrectly, including the use of invalidated iterators and the use of iterators of wrong STL types.

Example

 using namespace std;

 void test1(vector<string>& v1, vector<string>& v2) {
   vector<string>::iterator it = v1.begin();
   v2.erase(it); // iterator of wrong class instance is used
 }

Go warning types

Those checkers are developed for searching error specific for Go language.

UNINIT.GLOBAL_VAR

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownGOYes

In Golang most uninitalized errors were eliminated by language design but it is still possible for global variables. This checker finds situation where global variable is used without any initialization.

Example

var gvar1 map[string]string 
var gvar2 map[string]string 

func init()  {
    gvar1 = make(map[string]string)
    //gvar2 is not initialized
}

func use(name string, value string) {
    gvar1[name] = value
    gvar2[name] = value //error
}

LOOPVAR_IN_CLOSURE

Situation Severity Reliability Supported languages Enabled by default
QualityUndefinedUnknownGOYes

It searchs for using of loop variable in goroutine. Value of this variable may be changed by outer loop before this goroutine's execution which lead to race condition.

Example

    var synchr sync.WaitGroup
    for i := 0; i < 100; i++ {
        synchr.Add(1)

        go func() {
            defer synchr.Done()
            fmt.Printf("i = %d\n", i) 
        }()
    }
    synchr.Wait()

DEREF_OF_NULL.RET.GO_INTERFACE

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownGOYes

Interfaces are not pointers in Go even though they may look like pointers, and an interface variable will be "nil" only when its type and value fields are "nil". This can lead to unexpected behavior when checking an interface variable for "nil".

The checker detects situations where a pointer, which might be "nil", is converted to a value of interface type. The checker does not analyze caller code.

Example

func foo(x int) Interface {
    var possibleNil *Struct
    if (x > 5) {
        possibleNil = &Struct{Field: 5}
    }
    return possibleNil
}

INFINITE_LOOP.GOROUTINE

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownGOYes

This checker finds infinite loop in goroutines.

Example

func waiter(text string) { 
    for {
        time.Sleep(time.Second)
        fmt.Println(text)
    } //no exit condition
}

func main() {
    go waiter("Hello")
    go waiter("World")
    time.Sleep(50 * time.Second)
}

UNCHECKED_TUPLE.RET

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownGOYes

The checker detects situations where tuple result from functions with error part is used without checking error.

Example

func parse(path string) (uint, error) {
    length := read(path)
    if length < 0 {
        return 0, fmt.Errorf("error")
    }

    return  length, nil
}

func example(para string, out *int) uint {
    n, _ := parse(para)
    return n //error, variable 'n' is used without checking the error
}

UNSAFE_TYPE_SWITCH

Situation Severity Reliability Supported languages Enabled by default
QualityUndefinedUnknownGOYes

The checker finds situation where type-switch does not have default branch.

Example

    switch dm := m.(type) {
    case DynamicAny:
        m = dm.Message
    case *DynamicAny:
        if dm == nil {
            return nil, proto.ErrNil
        }
		m = dm.Message
    }
    //no default

Other warning types

FORMAT_STRING.PARAM_LACK

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++ JavaNo

This checker finds situations where a format string specifies more arguments than the number of arguments actually passed to a format output function. This leads to illegal access to stack memory.

Example

 void test(int x) {
   printf("count: %d/%d\n", x);
 }

See also

FORMAT_STRING.PARAM_EXCESS

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++No

This checker finds situations where a format string specifies less arguments than the number of arguments actually passed to a format output function.

Example

 void fmt_str(int x, int y, int z) {
   printf("count: %d/%d\n", x, y, z);
 }

See also

FORMAT_STRING.TYPE_MISMATCH

Situation Severity Reliability Supported languages Enabled by default
QualityMinorUnknownC/C++No

This checker finds situations where a format string specificator's type does not match the type of the corresponding actual argument passed to a format input or output function.

Example

 void f(int x) {
   printf("%s\n", x);
 }

RETURN_LOCAL_VAR

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalVeryHighC/C++Yes

This warning is emitted when pointer to a local variable is returned from a function. Memory referenced by such pointers is invalid, and using it may lead to inconsistent behavior.

Example

 int* ret(int* pa, int flag) {
   int def = -1;
   int* p = &def;
   if(flag)
     p = pa;
   return p; // here p may reference local variable 'def'
 }

NO_RETURN_VALUE

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++Yes

This checker finds functions in the source code that are declared as having a non-void return value, but don't return any value. This checker only detects such function that don't unconditionally terminate execution of the program.

Example

 void boo();

 int foo(void) {
   boo(); // NO_RETURN_VALUE will be emitted here
 }
 int foo2(int cond) {
   if(cond)
     exit(1);
   else
     exit(0);
 
   // NO_RETURN_VALUE will NOT be emitted here, since the function always terminates the program
 }

PROC_ADDR_NULL_CHECK

Situation Severity Reliability Supported languages Enabled by default
QualityMinorVeryLowC/C++Yes

This warning is emitted when function pointer known to be pointing to some particular function(s) is compared to NULL. Such comparison is always false.

Example

 int fun() {
   return 1;
 }

 typedef int (*PF)();

 void proc() {
   PF addr = &fun;

   if(addr==0) // condition is always false, emit PROC_ADDR_NULL_CHECK
     return;

   addr();
 }

Sometimes such comparison is intended. To suppress this warning, change 0 to a constant with NULL value:

 int fun() {
   return 1;
 }

 typedef int (*PF)();

 void proc() {
   PF addr = &fun;

   int (*null_fp)(char const *) = 0;

   if(addr==null_fp) // PROC_ADDR_NULL_CHECK is not emitted
     return;

   addr();
 }

(Svace still emits PROC_ADDR_NULL_PTR_CHECK in this case.)

PROC_PAR_BIG

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++No

This checker finds situations where a structure of size greater than 16 bytes is passed as a function parameter by value.

See also

PROC_PAR_HUGE

Situation Severity Reliability Supported languages Enabled by default
QualityNormalHighC/C++Yes

This checker finds situations where a structure of size greater than 128 bytes is passed as a function parameter by value. Passing structures of such size by value can slow down a program significantly.

See also

STACK_EXCEED

Situation Severity Reliability Supported languages Enabled by default
QualityMinorHighC/C++Yes

This checker finds situations where the total size of memory that might be simultaneously allocated on stack exceeds the allowed bound (8 MB by default on Linux).

Example

 void bigmem() {
   char arr7mb[7 * 1024 * 1024];
   ...  
 }

 void test() {
   char arr2mb[2 * 1024 * 1024];
   ...
   bigmem();
   ...
 }

See also

LOCAL_VAR.BIG

Situation Severity Reliability Supported languages Enabled by default
QualityMinorLowC/C++Yes

This checker finds situations where the size of a variable or an array exceeds 100 KB.

See also

LOCAL_VAR.HUGE

Situation Severity Reliability Supported languages Enabled by default
QualityMinorAverageC/C++Yes

This checker finds situations where the size of a variable or an array exceeds 1 MB.

See also

BOOLEAN_INVARIANT

Situation Severity Reliability Supported languages Enabled by default
QualityUndefinedUnknownC/C++ JavaNo

This warning is emitted when result of comparison is always true or always false on all possible execution paths that pass through the conditional expression.

Example

 int func(int a) {
   if(a<-1 && a<0) // if a<-1 then a<0 is always true, emit BOOLEAN_INVARIANT
     return -1;

   if(a==3)
     if(a>2) // if a==3, a>2 is always true
       return -2;

   if(a>=0 && a<0) // if a>=0, a<0 is always false
     return -3;

   return 0;
 }

INVARIANT_RESULT

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++ Java C#Yes

This checker reports a suspicious expression where the result of operation is always a constant regardless of the value of its variable operands.

Example

 int func(unsigned char c) {
   if (c > 1024) { // Always false since unsigned char type has possible value in the range of [0; 255]
     return -1;
   }
 }

Subtypes of this warning INVARIANT_RESULT.OP_ASSIGN and INVARIANT_RESULT.OP_ZERO indicate the use of a composite logic assignment operator and logic operator with zero operands respectively. Such patterns are separated to contain possible false positives when constant macros are used.

Example

In the following example, bitwise AND is applied with zero.

  unsigned flags = 5;
  if (flags & 0) { 
    ...
  }

Example

In the following example, a logical operator "!" appears to have been substituted for a bitwise operator "~".

  int supposedToBeBitwiseComplementOfFLAGS = !FLAGS;

Example

In the following example, parentheses are missed.

  !var & FLAGS

Example

In the following example, the right-hand side of an |= expression is of a wide type than the left-hand side and has high-order bits set that will not affect the left-hand side.

  short_variable |= 0x10000;

REDUNDANT_NULL_CHECK

Situation Severity Reliability Supported languages Enabled by default
QualityMinorUnknownC/C++ JavaNo

This warning is emitted when result of comparison is always true or always false on all possible execution paths that pass through the conditional expression. This warning is similar to BOOLEAN_INVARIANT but REDUNDANT_NULL_CHECK is intra-procedural and takes math operations into account.

Example

 int glob;

 int bar(int k){
   if(k > 0)
     glob = 5;
   return 0;
 }

 int func(int a) {
   glob = 0;
   if(glob) //always false, REDUNDANT_NULL_CHECK emitted
     return 0;

   int f = bar(a);
   
   if(glob) //unknown, REDUNDANT_NULL_CHECK not emitted
     return 0;

   f += 5;
   if(f > 2) //always true, REDUNDANT_NULL_CHECK emitted
     return 0;

   return 0;
 }

CHECK_AFTER_PASS_TO_PROC

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++ JavaYes

This checker finds situations where a value is first used by passing it to a function as an argument, and then is checked for potentially being negative afterwards, meaning that such value may indicate an error code.

Example

 int foo(int fd) {
   int status = dup(fd);
 
   if (fd != -1) {
     return status;
   }

   return -1;
 }

BAD_COMPARE

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++Yes

This checker finds suspicious 'lesser than' and 'greater than' comparisons between a pointer and a null pointer.

Example

 void foo(void *p) {
   // ...
   if (p >= NULL) // probably, p != NULL was intended
     return;
   // ...
 }

UNREACHABLE_CODE

Situation Severity Reliability Supported languages Enabled by default
QualityNormalAverageC/C++ Java KOTLIN C# GOYes

This checker finds source code that can't be executed because control flow path to the code from the rest of the program is unfeasible.

Example (C/C++)

 void foo(int i);

 void unreachable(int cond) {
   if(cond) {
     printf("error!\n");
     exit(1);
   } else {
     exit(0);
   }
   foo(15); // UNREACHABLE_CODE
 }

The program is terminated on all paths leading to the call of 'foo' function. The function call will never be executed.

Example (Kotlin)

fun example(a: Int) {
    when {
        a > 10 -> print("a > 10")
	a <= 10 -> print("a <= 10")
        else -> print("unreachable")
    }
}

fun possibleFix(a: Int) {
    when {
        a > 10 -> print("a > 10")
	a <= 10 -> print("a <= 10")
    }
}

'else' branch in 'when' expression is unreachable because first and second branches cover all possible values of 'a'. Just remove redundant branch to fix this defect.

See also

UNREACHABLE_CODE.ENUM

Subtype of UNREACHABLE_CODE for switch with enum variable. All possible values are enumerated by case labels. The warning is emitted for default label. Note: it is a good practice to always write default label.

enum E {
    aa1,
    aa2,
    aa3
};

void example(enum E x) {
    int a = 1;

    switch(x) {
    case aa1: a = 2; break;
    case aa2: a = 4; break;
    case aa3: a = 5; break;
    default: a = 22; break;//UNREACHABLE_CODE.ENUM
    }
}

UNREACHABLE_CODE.SWITCH

Subtype of UNREACHABLE_CODE for situations where case label of switch is unreachable.

void example(enum E x) {
    if(x==aa2)
        return;

    int a;

    switch(x) {
    case aa1: a = 2; break;
    case aa2: a = 4; break;//UNREACHABLE_CODE.SWITCH
    case aa3: a = 4; break;
    default: a = 22; break;//UNREACHABLE_CODE.ENUM
    }
}

UNREACHABLE_CODE.DEFAULT

Subtype of UNREACHABLE_CODE for situations where default label of switch is unreachable. Situations with enum variables are not related to this type. UNREACHABLE_CODE.ENUM is emitted for them.

void example1(int x) {
    if(x<0 || x>4) {
        return;
    }

    int a = 1;

    switch(x) {
    case 0: a = 2; break;
    case 1: a = 4; break;
    case 2: a = 5; break;
    case 3: a = 3; break;
    case 4: a = 12; break;
    default: a = 22; break;//UNREACHABLE_CODE.DEFAULT
    }
}

In follow code snipped programmer may assume that default label include cases where variable x is equal to aa3.

enum E {
    aa1,
    aa2,
    aa3
};

void example2(int z) {
    enum E x = aa1;
    if(z==3)
        x = aa2;

    int a;

    switch(x) {
    case aa1: a = 2; break;
    case aa2: a = 4; break;
    default: a = 22; break;//UNREACHABLE_CODE.DEFAULT
    }
}

INT_TO_CHAR

Situation Severity Reliability Supported languages Enabled by default
QualityNormalAverageC/C++Yes

Some C functions, such as getc, fgetc and getchar, return either (non-character) value EOF or a character code. This checker detects incorrect use of such functions, where their return value is not compared to EOF before being converted from int to char (note that comparing to EOF after converting to type char is incorrect, since integer value of EOF is not a char).

Example

 char buf[256];
 FILE* fp;
 int c, i=0;

 void test() { 
   while(i<256) {
     c = fgetc(fp);
     if(c=='q')
       break;

     buf[i++] = c; // unsafe type conversion, not checked for EOF
   }
 } 

PROC_USE.VULNERABLE

Situation Severity Reliability Supported languages Enabled by default
QualityMinorHighC/C++Yes

This warning is emitted for invocations of functions that open security vulnerabilities, irrespective of their method of use.

A subtype of this warning PROC_USE.VULNERABLE.TEMP indicates the use of vulnerable library functions for working with temporary files.

Example

 void vln_use() {
   char buf[10000];
   gets(buf); // no matter what is the size if 'buf', 'gets' can overflow it.
 }

TOCTTOU_SEQUENCE

Situation Severity Reliability Supported languages Enabled by default
QualityMinorUnknownC/C++No

The checker TOCTTOU_SEQUENCE (Time-of-check-to-time-of-use) finds situations where a call accessing file attributes (such as stat(), access() and readlink()) is followed by a call using the same file (such as fopen(), opendir()). This can potentially lead to a kind of race condition, where between the check of file attributes and use of the file, the file is changed.

Example

 void test(const char* fname) {
   if(access(fname, W_OK) == 0)
     open(fname, O_WRONLY);
 }

CHROOT_JAIL

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++Yes

This checker finds situation where a call to chroot() is made, that isn't followed by a call to chdir("/"). Function chroot() limits application's access to the file system to within a given directory ("sandbox"). However, if current directory is outside the sandbox, the application can still access files outside the sandbox. Calling chdir("/") makes sure it doesn't happen.

This checker can handle source code that implements calls to 'chdir' and 'chroot' using wrapper functions, or code that calls 'chdir' conditionally on the return value of 'chroot'.

Example

 int chroot_wrapper() {
   return chroot("/var/jail");
 }
  
 int chdir_wrapper() {
   return chdir("/");
 }
  
 void a(int b, int c) {
   chroot_wrapper();
   if(b>c)
     chdir_wrapper(); // CHROOT_JAIL is emitted here, since 'chdir' 
                      // doesn't follow 'chroot' unconditionally
   fopen("/etc/passwd", "r");
 }

NEGATIVE_CODE_ERROR

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++ JavaYes

The checker NEGATIVE_CODE_ERROR finds situations where a value is returned by a library function, that may be negative to indicate an error code, but is used in a situation where the negative values are not expected (for example, in a call to another function, or as an index in buffer access).

Example

 void test(char* path, int flags, char* mode, char* buf, int nbytes) {
   int x = open(path, flags, mode);
   read(x, buf, nbytes);
 }

The value returned by open() may be a negative error code, which shouldn't be passed to function read().

UNCHECKED_FUNC_RES.LIB

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++ Java KOTLINYes

The checker UNCHECKED_FUNC_RES.LIB and its subtypes find situations where a function return value that may indicate an error is ignored.

Example(С/C++)

 void unchecked_func_res_lib(FILE *f) {
   fseek(f, 8, SEEK_SET); // Ignored the return value
}

If some variable assigns the result of such function call then the 'UNCHECKED_FUNC_RES.LIB' will be emitted.

Example(Kotlin)

fun example(string: String, offset: Int): Reader {
    val reader = StringReader(string)
    val skipped = reader.skip(offset.toLong())
    return reader
}

If the result of such function call is not assigned to any variable then the 'UNCHECKED_FUNC_RES.LIB.STRICT' will be emitted.

Example(Kotlin)

fun example(string: String, offset: Int): Reader {
    val reader = StringReader(string)
    reader.skip(offset.toLong())
    return reader
}

To fix the defects of these types check the return values that may indicate an error code.

Example(Kotlin)

fun possibleFix(string: String, offset: Int): Reader {
    val reader = StringReader(string)
    if (reader.skip(offset.toLong()) < 0) {
        //
    }
    return reader
}

UNINIT.LOCAL_VAR

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++Yes

This checker finds situations where a value of locally defined (automatic) variable is accessed, but the variable was never initialized.

Example

 struct X {
   int fld;
 };
 
 void uninit() {
   struct X st;
   int val;
 
   val = st.fld;
 }

Variable st.fld accessed at the last line was never initialized.

See also

UNINIT.LOCAL_ARRAY

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++No

This checker finds situations where a member of locally defined (automatic) array is accessed, but it was never initialized.

Example

 struct X {
   int fld;
 };
 
 void uninit() {
   struct X st[10];
   int val;
 
   val = st[5].fld;
 }

Array member st.fld[5] accessed at the last line was never initialized.

See also

UNINIT.HEAP_VAR

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++No

This checker finds situations where a value is read from uninitialized dynamically allocated memory block.

Example

 struct T {
   int a;
 };

 void uninit_var() {
   struct T* t = (struct T*)malloc(sizeof(struct T));
   int val;
 
   val = t->a;
 }

Memory allocated by function malloc was never initialized, but is accessed by expression t->a.

See also

NON_VIRTUAL_DTOR

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++No

This checker finds situations where a derived class directly uses dynamic memory, but its base class (with public inheritance) doesn't have a virtual destructor. Deallocating objects of such classes through a pointer to the base class fails to invoke derived class' destructor, and so can result in a memory leak.

Example

 class Base {
 public:
   ~Base() {} // a non-virtual destructor
 };

 //public inheritance
 class Child : public Base {
   int* arr;
 public:
   Child() {
     arr = new int[10];
   }
   virtual ~Child() {
     delete[] arr; // this instruction works with dynamic memory; 
                   // NON_VIRTUAL_DTOR will be emitted at this line
   }
 };

 void use() {
   Base* b = new Child();
   delete b; // a memory leak example: only Base::~Base is invoked here
 }

Notes

Svace emits a warning even if source code never deletes objects of the derived class via a pointer to base class. Svace shouldn't detect situations with private or protected inheritance. We plan to include traces with location of base class, inheritance chain, and delete location in future versions of the checker.

NO_CATCH

Situation Severity Reliability Supported languages Enabled by default
QualityNormalHighC/C++Yes

This checker finds situations where some function throws exceptions which should not be thrown from it because of specified exception list, or because the function is a top-level function, or because the function is a destructor.

If some exception does not correspond to specified exception list of some function then the program will crash.

Example

void foo() throw(int) {
  throw "Hello world!"; // Warning is fired
}

int main() {
  try {
    foo();
  } catch(...) {
    // Never reached
  }
}

Exceptions from main function also terminate the program.

Example

int main() {
  throw "Hello world!"; // Warning is fired
}

Throwing an exception out of a destructor is dangerous. If another exception is already propagating the application will terminate.

Example

  struct Bad {
    ~Bad(){
      throw 1; // Warning is fired
    }
  };

  int main() {
    try {
      Bad bad;
      throw 2;
    } catch(...){
      // Never reached
    }
  }

NO_CATCH.LIBRARY

Situation Severity Reliability Supported languages Enabled by default
QualityNormalVeryLowC/C++Yes

This warning is emitted in the same patterns as described above but only if the exception could be thrown from some standard library function or operator.

Example

class Base {virtual void member(){}};
class Derived : Base {};

void test() throw() {
  Base b;
  // will crash, because dynamic_cast of reference could throw std::bad_cast
  Derived& rd = dynamic_cast<Derived&>(b);
}

In some cases the standard library specification declares that some exception is possible but actually it could never be thrown. The warnings of such cases are NO_CATCH.LIBRARY.PEDANTIC type. For example, std::string constructors assumes that there is some maximal capacity of the string that could be less than the size of addressable memory. So, if the user asks std::string to create a string with the size more than this maximal capacity, then std::string constructor will throw std::length_error. In most standard library implementations the maximal capacity is equal to the size of addressable memory and so there will be std::bad_alloc exception, not std::length_error, for too big strings.

Example

  std::string s3 ('x', 10); //theoretically can throw std::length_error

NO_CATCH.BAD_ALLOC

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++No

The most used version of operator new cannot return NULL but instead could throw std::bad_alloc exception in the case when it could not allocate memory. Most programs don't catch possible std::bad_alloc's because they assume that there is enough memory. So std::bad_alloc exception has own warning type.

VARIABLE_IS_NOT_ARRAY

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++Yes

This checker finds situations where the address of some not-array variable is used as array.

Example

void set(int* buf) {
    buf[10] = 0;
}

int test1() {
    int x = 0;
    set(&x); // There will be memory access violation
    return x;
}

COMPARE_RESULT_OF_NEW

Situation Severity Reliability Supported languages Enabled by default
QualityMinorAverageC/C++Yes

This checker finds situations where the value returned by operator new is compared with NULL.

Example

 void foo() {
   char *x = new char[10];
   if (x) { //this check is redundant
     //...
   }
 }

UNCHECKED_FUNC_RES.STAT

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++ Java KOTLINYes

This checker finds situations where return value of some function is not checked, while it's checked in most places where that function is called. The warning is emitted according to statistics of function use, without taking into account function's body (implementation). Compared to DEREF_OF_NULL.RET.USER, this checker relies on function use statistics to a greater extent, and works with more types of return value checks than just comparison with NULL. This checker emits warning if more than 'UNCHECKED_FUNC_RES.STAT.THRESHOLD' percents of all such function calls are checked. 'UNCHECKED_FUNC_RES.STAT.THRESHOLD' configuration variable is equal to 80% by default.

Example (Kotlin)

class Stat() {
    var isReady = false
    var counter = 0
    fun inc(): Boolean {
        counter++
        return isReady
    }
    // ...
}

fun checkedA(s: Stat) {
    if (s.inc()) {
        println("checked in A")
    }
}

fun checkedB(s: Stat) {
    if (s.inc()) {
        println("checked in B")
    }
}

fun unchecked(s: Stat) {
    s.inc()
}

The 'UNCHECKED_FUNC_RES.STAT' warning will be emitted for 'inc' call into 'unchecked' function. Note that 'UNCHECKED_FUNC_RES.STAT.THRESHOLD' is set to 65% for this example. Possible fix: check the return value of 'inc' call into 'unchecked' function.

CLIB.OPEN.MODE

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++Yes

This checker finds situations where standard library function 'open' is invoked with flag O_CREAT, but without passing it the third parameter.

 int open(const char* path, int oflag, ... );

Here if 'oflag' is O_CREAT, it's necessary to specify the 3rd argument to set correct file access rights.

NO_VA_END

Situation Severity Reliability Supported languages Enabled by default
QualityNormalVeryHighC/C++Yes

This checker finds situations where 'va_end' is missing from functions that work with variable argument lists.

Example

 int no_va(int x, ...) {
   va_list va;
   va_start(va, x);
   if(va_arg(va, int) == x)
     return -1; // va_end call is missing
   va_end(va);
 }

See also

NO_VA_START

Situation Severity Reliability Supported languages Enabled by default
QualityNormalVeryHighC/C++Yes

This checker finds situations where 'va_start' is missing from functions that work with variable argument lists.

Example

 void test(int x, ...) {
   va_list va;
   if(x!=0)
     va_start(va, x);
   while(x>0) {
     ...
     x--;
   }
   va_end(va);
 }

See also

BAD_COPY_PASTE

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++ Java C#Yes

This checker locates code snippets that were copied and pasted. However, because of incomplete change, they unintentionally left some portions of the copy unchanged.

Example

 int square(int x) {
   return x * x;
 }

 int foo(int a, int b, int x, int y) {
   int result = 0;
   if (b > 0) {
     result = square(a) + square(x); // defect: value 'a' might be 'b'
   }
   if (a > 0) {
     result = square(a) + square(x); // original code
   }
   return result;
 }

SIMILAR_BRANCHES

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++ Java C#Yes

This checker reports a warning when both true and false branches of a conditional operator are identical.

Example

 void foo1(bool c){
   int i;
   if (c)
     i = 1; // Same code
   else
     i = 1; // Same code
 }

CONFUSING_INDENTATION

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++ Java C#Yes

This checker finds many cases where the indentation structure of the code does not match the syntactic nesting.

Example

 void foo(int a, int b) {
   if (a > b)
     b++;
     a++; // Doesn't belong to the 'if' body but indentation suggests it is
 }

UNUSED_FUNC_RES

Situation Severity Reliability Supported languages Enabled by default
QualityMinorUnknownC/C++ JavaNo

This checker finds situations when a pointer returned from a function call is saved in a local variable, but is never used afterwards.

Example

 typedef struct {
   int mem;
 } storage, something;

 storage* add_something_to_storage(storage*, something*);

 void process(storage* stor, something* smt) {
   storage* new_stor = add_something_to_storage(stor, smt);
   ...
   /* use stor instead of new_stor */
   ...
   return;
 }

UNUSED_VALUE

Situation Severity Reliability Supported languages Enabled by default
QualityMinorAverageC/C++ JavaYes

This checker finds situations when a variable is initially assigned a value but is always reassigned a new value before using the original one.

Example

 void func(int *x) {
   int value;
   value = 1; // This value is never used
   value = 2;
 }

BAD_SIZEOF

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++Yes

Check for isolated occurrences of sizeof operators that are technically legal in C/C++, yet are often erroneous.

Example 1

In the following example, param_not_really_an_array looks syntactically like an array, but is actually a pointer. When you apply the sizeof operator to the pointer, it yields the size of a pointer (typically 4 or 8 bytes), and not the expected 10 bytes:

  void f(char param_not_really_an_array[10]) {
    memset(param_not_really_an_array, 0, sizeof(param_not_really_an_array));
  }

Example 2

In the following example, sizeof is applied to the this pointer rather than to the *this object, which yields an incorrect value for the size of the object:

  size_t SomeClass::getObjectSize() const {
    return sizeof(this);
  }

Example 3

In the following example, the sizeof operator is applied to the address of s rather than to s itself, which yields a larger value and overwrites adjacent memory locations:

  void f() {
    short s;
    memset(&s, 0, sizeof(&s));
  }

Example 4

In the following example, the sizeof operator is applied to the pointer arithmetic expression buf – 3. The expression has type char* and is likely 4 or 8 bytes in size, rather than sizeof applied to buf, and then subtracting 3 from the result, which yields the desired value of 97:

  void f() {
    char buf[100];
    buf[0] = 'x';
    buf[1] = 'y';
    buf[2] = 'z';
    memset(buf + 3, 0, sizeof(buf - 3));
  }

SIZEOF_POINTER_TYPE

Situation Severity Reliability Supported languages Enabled by default
QualityCriticalAverageC/C++Yes

Check for combinations of pointers and sizeof expressions that appear to be mismatched.

Example 1

In the following example, only 4 or 8 bytes of the 100-byte object buf are cleared:

  struct buffer {
    char b[100];
  };

  void f() {
    struct buffer buf;
    memset(&buf, 0, sizeof(&buf)); /* Defect: should have been “sizeof(buf)” */
  }

Example 2

In the following example, only 4 or 8 bytes are allocated for a 100-byte object:

  struct buffer {
    char b[100];
  };

  void f() {
    struct buffer *p = (struct buffer *)malloc(sizeof(struct buffer *));
    /* Defect: should be “sizeof(struct buffer)” */
  }

BAD_OVERRIDE

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++Yes

Check for defects in overriding virtual functions due to missing 'const' modifiers, which result in type signature mismatches.

Example

  class base {
    virtual void foo() const {/*...*/}
  };

  class child: public base {
  /* Warning: child::foo is probably meant to override base::foo but
    type signatures don't match perfectly */
    void foo() { /* ... */ }
  };

DELETE_VOID

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++No

Check for cases where a delete is applied to a pointer to void.

Example

In the following example, delete is used on a pointer of type void:

  void buggy(void *p) {
    delete p;
  }

EVALUATION_ORDER

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++Yes

Check for places in the code where the C/C++ language rules for expression evaluation do not determine the order in which side effects happen.

Example 1

In the following example, it is unclear whether the left or right side of the operator is evaluated first, so the value of x might change:

  int g(int x) {
    return x + x++;
  }

Example 2

The following example demonstrates side effect ordering problems. The right hand side of the assignment is evaluated before the assignment itself takes place. However, the side effect order is unspecified because the side effect associated with ++ could happen before or after the side effect associated with the assignment.

  int foo() {
    int x = 0;
    x = x++;
    return x;
  }

NO_EFFECT

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++ KOTLINYes

Check for instances of statements or expressions that do not accomplish anything, or statements that perform an action that is not the intended action.

Example 1

In the following example, the left operand of a comma operator has no side effects:

  void extra_comma() {
    int a, b;
    for (a = 0, b = 0; a < 10, b < 10; a++, b++);
    // Extra comma, and so a < 10 is not used
  }

Example 2

In the following example, only the first pointer is deleted:

  void incomplete_delete() {
    int *p, *q;
    delete p, q;
    // The pointer q is not deleted
  }

Example 3

In the following example, dereference of the pointer is useless:

  void no_effect_deref() {
    int *p;
    *p++;
    // *p is useless
  }

Example 4

In the following example, the boolean test is useless:

  void no_effect_test() {
    int a, b;
    a == b;
    /* Test has no effect, and is
    likely intended to be the assignment a = b */
  }

Example 5

In the following example, an assignment is likely intended:

  int a, b;
  void bool_switch() {
    switch (a == b) {    // Boolean switch
    case 1:
    }
  }

Example 6

In the following example, there's an unsigned comparison against 0:

  void unsigned_compare() {
    unsigned int a;
    if (a < 0)    // a is unsigned, and so the comparison is never true
      a++;
  }

Example 7

In the following example, there're self assignments:

  int a;
  void self_assign(struct foo *ptr) {
    a = a;
    ptr->x = ptr->x;
  }

Example 8

  void array_null() {
    unsigned int a[3];
    unsigned int b[1];
    unsigned int c[2];
    if (*a == 0)
      a[0];
    if (b == 0)       // The entire array b is compared to 0.
      b[1];
    if (c[1] == 0)
      c[1];
  }

Example 9

In the following example, suspicious arguments are passed to the memset function. A size argument of 0 can indicate that the size and fill arguments are switched. A fill value outside the range of -1 to 255 will likely lead to truncation. A fill value of '0' is likely intended to be 0:

  void bad_memset() {
    int *p;
    memset(p, '0', l);    // Fill value is '0', and 0 is more likely
    memset(p, l, 0);      // Length is 0, and so likely that l and 0 reversed
    memset(p, 0xabcd, l); /* Fill is truncated, and so memory
                             will not contain the 0xabcd pattern */
  }

WRONG_SEMICOLON

Situation Severity Reliability Supported languages Enabled by default
QualityMajorUnknownC/C++ Java C#Yes

Check for instances where an extraneous semicolon alters the logic of the code.

Example 1

In the following example, an if statement is followed by an extra semicolon, which results in do_something_conditionally() being called unconditionally:

  if (condition);
    do_something_conditionally();

Example 2

In the following example, a while statement is followed by an extra semicolon. The following block is executed only once, unconditionally, which might result in a premature return from the function:

  while (condition);
  {
    if (other_condition)
      return;
    /* advance the loop */
  }

INFINITE_LOOP

Situation Severity Reliability Supported languages Enabled by default
QualityMajorAverageC/C++ C#Yes

Check for instances of loops that never terminate due to control variables which are not properly updated.

Example 1

In the following example, a wrong variable is updated

  for (i = 0; i < n; ++j) { 
    ... 
  }

Example 2

In the following example, a wrong variable is updated:

  while (i > 0) {
    a[i] = i;
    --j;
  }

Example 3

In the following example, a wrong variable is updated:

  for (;;) {
    ++y;
    if (x > 5)
      break;
  }

DIVISION_BY_ZERO

Situation Severity Reliability Supported languages Enabled by default
QualityMajorLowC/C++ Java GOYes

Check for instances of divisions where the divisor (denominator) is zero.

Example 1

  int x = 0;
  int z = y / x;

Example 2

  x = 1;
  if (y) {
    x = 0;
  }
  z = y / x;

DIVISION_BY_ZERO.EX

Situation Severity Reliability Supported languages Enabled by default
QualityMajorHighC/C++ Java KOTLIN GOYes

Path sensitive version of the DIVISION_BY_ZERO. It checks if a path exists where some variable is assigned zero, and then this variable is used as a divisor.

Example (Kotlin)

fun example(cond: Boolean, value: Int) {
    val d: Int = if (cond) 10 else 0
    print(value / d)
}

fun possibleFix(cond: Boolean, value: Int) {
    val d: Int = if (cond) 10 else 0
    if (d != 0) {
        print(value / d)
    }
}

Function 'example' illustrates the defect: variable 'd' is maybe assigned zero, but this variable is used as a divisor also. Function 'possibleFix' illustrates a possbibleFix: check 'd' value before using it as a divisor.

NO_BASE_CALL.LIB

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++ Java C#Yes

This checker finds situations where a method is overriden and the overriding method should call the superclass. The checker relies on function for which all overriders should call the superclass.

Example (Kotlin)

import android.app.Activity

class Child : Activity() {
    override fun onDestroy() {
        super.onPause()
    }
}

class CorrectChild : Activity() {
    override fun onDestroy() {
        super.onDestroy()
    }
}

The 'NO_BASE_CALL.LIB' warning will be emitted for function 'Child.onDestroy', because it calls unsuitable 'Activity.onPause' superclass method. Possible fix: call proper 'onDestroy' superclass method as shown in 'CorrectChild?.onDestroy' method.

NO_BASE_CALL.STAT

Situation Severity Reliability Supported languages Enabled by default
QualityNormalUnknownC/C++ Java KOTLIN C#Yes

This checker finds situations where a method is overriden and the overriding method should call the superclass method. This checker emits warning if more than 'CALL_SUPER.STAT.THRESHOLD' percents of all overriders call the superclass method. 'CALL_SUPER.STAT.THRESHOLD' configuration variable is equal to 80% by default.

Example (Kotlin)

open class Base {
    open fun foo(msg: String) = println(msg)
}

class DerivedA : Base() {
    override fun foo(msg: String) = super.foo("from A: $msg")
}

class DerivedB : Base() {
    override fun foo(msg: String) = super.foo("from B: $msg")
}

class DerivedC : Base() {
    override fun foo(msg: String) = println("derived C: $msg")
}

The 'NO_BASE_CALL.STAT' warning will be emitted for function 'foo' overriden into 'DerivedC' class. Note that 'CALL_SUPER.STAT.THRESHOLD' is set to 65% for this example. Possible fix: call super method in 'DerivedC.foo' method.

Java analysis

Analysis of Java source code can be performed using SpotBugs analysis tool, which is automatically invoked by Svace analysis tool by default. Filtering of warning types imported from SpotBugs can be configured using svace warning command, in the same way as for Svace warnings. The following SpotBugs checkers are supported (their descriptions can be found on the SpotBugs bug descriptions page):

FB.BC_IMPOSSIBLE_CAST
FB.BC_IMPOSSIBLE_INSTANCEOF
FB.ES_COMPARING_PARAMETER_STRING_WITH_EQ
FB.ES_COMPARING_STRINGS_WITH_EQ
FB.ML_SYNC_ON_FIELD_TO_GUARD_CHANGING_THAT_FIELD
FB.ML_SYNC_ON_UPDATED_FIELD
FB.UL_UNRELEASED_LOCK_EXCEPTION_PATH
FB.CN_IDIOM
FB.DB_DUPLICATE_BRANCHES
FB.DL_SYNCHRONIZATION_ON_BOOLEAN
FB.DL_SYNCHRONIZATION_ON_BOXED_PRIMITIVE
FB.DM_EXIT
FB.DMI_INVOKING_HASHCODE_ON_ARRAY
FB.DMI_INVOKING_TOSTRING_ON_ARRAY
FB.DMI_RANDOM_USED_ONLY_ONCE
FB.DMI_THREAD_PASSED_WHERE_RUNNABLE_EXPECTED
FB.EC_ARRAY_AND_NONARRAY
FB.EC_BAD_ARRAY_COMPARE
FB.EC_UNRELATED_CLASS_AND_INTERFACE
FB.EC_UNRELATED_TYPES
FB.EQ_ALWAYS_FALSE
FB.EQ_OVERRIDING_EQUALS_NOT_SYMMETRIC
FB.EQ_SELF_USE_OBJECT
FB.ESYNC_EMPTY_SYNC
FB.FE_FLOATING_POINT_EQUALITY
FB.FI_EXPLICIT_INVOCATION
FB.GC_UNRELATED_TYPES
FB.ICAST_IDIV_CAST_TO_DOUBLE
FB.ICAST_INTEGER_MULTIPLY_CAST_TO_LONG
FB.IL_INFINITE_LOOP
FB.IL_INFINITE_RECURSIVE_LOOP
FB.INT_BAD_COMPARISON_WITH_SIGNED_BYTE
FB.INT_BAD_REM_BY_1
FB.IP_PARAMETER_IS_DEAD_BUT_OVERWRITTEN
FB.JLM_JSR166_UTILCONCURRENT_MONITORENTER
FB.LI_LAZY_INIT_STATIC
FB.LI_LAZY_INIT_UPDATE_STATIC
FB.MF_CLASS_MASKS_FIELD
FB.MWN_MISMATCHED_NOTIFY
FB.MWN_MISMATCHED_WAIT
FB.NN_NAKED_NOTIFY
FB.NP_BOOLEAN_RETURN_NULL
FB.NP_SYNC_AND_NULL_CHECK_FIELD
FB.NP_UNWRITTEN_FIELD
FB.NS_DANGEROUS_NON_SHORT_CIRCUIT
FB.RC_REF_COMPARISON
FB.RC_REF_COMPARISON_BAD_PRACTICE
FB.RE_POSSIBLE_UNINTENDED_PATTERN
FB.REC_CATCH_EXCEPTION
FB.RPC_REPEATED_CONDITIONAL_TEST
FB.RV_DONT_JUST_NULL_CHECK_READLINE
FB.RV_EXCEPTION_NOT_THROWN
FB.RV_RETURN_VALUE_IGNORED
FB.RV_RETURN_VALUE_IGNORED_BAD_PRACTICE
FB.SA_FIELD_SELF_COMPARISON
FB.SA_LOCAL_SELF_COMPARISON
FB.SA_LOCAL_SELF_COMPUTATION
FB.SBSC_USE_STRINGBUFFER_CONCATENATION
FB.SC_START_IN_CTOR
FB.SF_DEAD_STORE_DUE_TO_SWITCH_FALLTHROUGH
FB.SF_DEAD_STORE_DUE_TO_SWITCH_FALLTHROUGH_TO_THROW
FB.SIC_INNER_SHOULD_BE_STATIC
FB.STCAL_INVOKE_ON_STATIC_CALENDAR_INSTANCE
FB.STCAL_INVOKE_ON_STATIC_DATE_FORMAT_INSTANCE
FB.STI_INTERRUPTED_ON_UNKNOWNTHREAD
FB.SWL_SLEEP_WITH_LOCK_HELD
FB.UCF_USELESS_CONTROL_FLOW_NEXT_LINE
FB.UG_SYNC_SET_UNSYNC_GET
FB.UR_UNINIT_READ
FB.UR_UNINIT_READ_CALLED_FROM_SUPER_CONSTRUCTOR
FB.UW_UNCOND_WAIT
FB.WA_AWAIT_NOT_IN_LOOP
FB.WA_NOT_IN_LOOP
FB.BC_BAD_CAST_TO_CONCRETE_COLLECTION
FB.BC_EQUALS_METHOD_SHOULD_WORK_FOR_ALL_OBJECTS
FB.BC_UNCONFIRMED_CAST
FB.BC_VACUOUS_INSTANCEOF
FB.BIT_IOR
FB.CN_IMPLEMENTS_CLONE_BUT_NOT_CLONEABLE
FB.DE_MIGHT_IGNORE
FB.DLS_DEAD_LOCAL_STORE
FB.DLS_DEAD_LOCAL_STORE_IN_RETURN
FB.DLS_DEAD_LOCAL_STORE_OF_NULL
FB.DM_BOOLEAN_CTOR
FB.DM_GC
FB.DM_NEXTINT_VIA_NEXTDOUBLE
FB.DM_NUMBER_CTOR
FB.DM_STRING_CTOR
FB.DM_STRING_VOID_CTOR
FB.DMI_HARDCODED_ABSOLUTE_FILENAME
FB.DMI_USELESS_SUBSTRING
FB.DMI_USING_REMOVEALL_TO_CLEAR_COLLECTION
FB.DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED
FB.EQ_CHECK_FOR_OPERAND_NOT_COMPATIBLE_WITH_THIS
FB.EQ_COMPARETO_USE_OBJECT_EQUALS
FB.EQ_DOESNT_OVERRIDE_EQUALS
FB.EQ_GETCLASS_AND_CLASS_CONSTANT
FB.EQ_UNUSUAL
FB.FI_EMPTY
FB.FI_FINALIZER_NULLS_FIELDS
FB.FI_PUBLIC_SHOULD_BE_PROTECTED
FB.FI_USELESS
FB.HE_EQUALS_USE_HASHCODE
FB.IA_AMBIGUOUS_INVOCATION_OF_INHERITED_OR_OUTER_METHOD
FB.ICAST_INT_CAST_TO_DOUBLE_PASSED_TO_CEIL
FB.ICAST_INT_CAST_TO_FLOAT_PASSED_TO_ROUND
FB.ICAST_QUESTIONABLE_UNSIGNED_RIGHT_SHIFT
FB.IM_AVERAGE_COMPUTATION_COULD_OVERFLOW
FB.IM_BAD_CHECK_FOR_ODD
FB.IMSE_DONT_CATCH_IMSE
FB.INT_VACUOUS_BIT_OPERATION
FB.NP_CLONE_COULD_RETURN_NULL
FB.NP_EQUALS_SHOULD_HANDLE_NULL_ARGUMENT
FB.NP_TOSTRING_COULD_RETURN_NULL
FB.RCN_REDUNDANT_COMPARISON_TWO_NULL_VALUES
FB.RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE
FB.RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE
FB.SA_FIELD_DOUBLE_ASSIGNMENT
FB.SA_FIELD_SELF_ASSIGNMENT
FB.SE_BAD_FIELD
FB.SE_BAD_FIELD_STORE
FB.SE_COMPARATOR_SHOULD_BE_SERIALIZABLE
FB.SE_NO_SERIALVERSIONID
FB.SF_SWITCH_FALLTHROUGH
FB.SS_SHOULD_BE_STATIC
FB.ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD
FB.UCF_USELESS_CONTROL_FLOW
FB.UMAC_UNCALLABLE_METHOD_OF_ANONYMOUS_CLASS
FB.UPM_UNCALLED_PRIVATE_METHOD
FB.URF_UNREAD_FIELD
FB.UUF_UNUSED_FIELD
FB.UWF_NULL_FIELD
FB.UWF_UNWRITTEN_FIELD
FB.WMI_WRONG_MAP_ITERATOR

Glossary

  • IR files - intermediate representation files generated by a compiler on the first stage of analysis from the source code, and used by the analysis tool.
  • Issue - an individual warning emitted by the analysis tool, associated with a location in the source code, a message explaining the suspected problem, and a warning type classifier.
  • Checker - a subsystem of the analysis tool responsible for detecting issues belonging to specific warning type, or to a group of related warning types.
  • Tainted value - a value of a variable in the analyzed program that is obtained during its execution from the network or from a file. Tainted values may be used by attackers to exploit security vulnerabilities.