figure a
figure b

1 Verification Approach

Goblint is a static analysis framework for C programs based on abstract interpretation [6]. It features scalable thread-modular analysis of concurrent programs on top of flow- and context-sensitive interprocedural analysis. The analysis is specified as a side-effecting constraint system [2], which can conveniently express flow-insensitive invariants as well as flow-sensitive information per program point [16] and is solved using a local generic solver [15]. Here, we detail some recent SV-COMP–related advances in Goblint. The previous competition tool paper [11] provides further details on the general approach.

New abstract domains have been added to enhance precision. In addition to interval analysis of integer variables, Goblint now performs interval analysis of floating-point variables following Miné [9], and maintains congruence information [7]. Furthermore, the Apron library [8] has been integrated for relational analysis. Goblint includes novel approaches to relational analysis of concurrent programs [14], inferring relations between jointly-protected global variables.

In the previous tool paper, we suggested dynamically tailoring Goblint to the program under analysis. This can increase precision, by activating analyses that are more expensive yet offer crucial precision, and also decrease resource usage, by deactivating redundant analyses. To this end, we have implemented analysis configuration autotuning based on cheap syntactic heuristics on the program, before the analysis begins. The particular features have been chosen according to how expert users might configure Goblint for a given program. Measurements of program size (e.g. number of functions, loops, variables) are taken into account to limit slowdown on larger programs.

Goblint provides a multitude of concurrency-related analyses (e.g. races, symbolic locking patterns, thread joins [14, 16]) that have no use in single-threaded programs which abound in SV-COMP. Hence, all such analyses are now automatically deactivated for programs that never create any threads.

Goblint implements a wide variety of numerical abstract domains, but most are not necessary for every program, thus, offering many possibilities for autotuning. Interval information is omitted in calling contexts of recursive functions to avoid an explosion of contexts in which they are to be analyzed. While the congruence domain is generally active on small programs, for medium-sized programs it is only enabled for functions involving the modulo operator, either directly or indirectly (up to fixed depth in the call stack). If the program uses enums, then an integer domain for sets of enumeration values is activated. Octagon analysis is enabled for those local variables which occur most often in linear expressions and conditions. Interval and octagon widening thresholds are extracted from conditional expressions containing constants. Such thresholds are especially useful for flow-insensitive analysis of global variables in multi-threaded programs, since no narrowing is performed on flow-insensitive invariants.

Loop unrolling is a well-known technique to increase the precision of static analysis. Goblint now unrolls loops up to their static bounds or feasible unrolled code size. Loops which contain memory allocation, thread creation, or error function calls, are prioritized since unique heap locations and threads are key to maintaining analysis precision.

Schwarz et al. [13] enhanced Goblint with a suite of concurrent value analyses and evaluated their precision. Following their observations, we use the cheap yet sufficiently precise Protection-Based Reading. Data-race detection was made more precise using may-happen-in-parallel analysis [14], to filter out spurious races with threads that have already been joined or have not yet been created.

2 Software Architecture

Goblint is implemented in OCaml and uses an updated fork of CIL [10] as its parser frontend for the C language. It depends on Apron [8] for relational analyses. No other major libraries or external tools are required.

Goblint employs a modular architecture [1] where a combination of analyses can be selected at runtime. Analyses are defined through their abstract domains and transfer functions, which can communicate with other analyses using predefined queries and events. The combined analyses together with the control-flow graphs of the functions yield a side-effecting constraint system [2], which is solved using a local generic solver [15]. The solution is post-processed to determine the verdict and construct a witness.

3 Strengths and Weaknesses

Goblint focuses on sound static analysis which is confirmed by the competition: our tool does not produce any incorrect results. A major limitation of our approach is that, due to over-approximation, the tool can only prove the absence of bugs, but not their presence. Thus, when Goblint flags a potential violation, it answers “unknown” in the competition.

In SV-COMP 2023, NoDataRace became an official category and existing ConcurrencySafety reachability tasks were newly included into it. This is where Goblint really shines: it proves 652 out of 783 programs race-free, thereby winning the category. Overall, the strengths and weaknesses of Goblint w.r.t. categories remain the same as described in our previous tool paper. Therefore, we describe here the impact of autotuning, based on our own preliminary comparative evaluation. Unlike official SV-COMP evaluation, we used a 1 GB memory limit, which is sufficient for most tasks Goblint can solve, and no witness validators.

As noted above, the majority of SV-COMP programs across all categories are single-threaded, thus, the greatest improvement comes from disabling all concurrency analyses in those cases. This yields a notable reduction in runtime and memory usage as shown in table 1, improving overall efficiency without compromising precision.

Table 1. Reduction in resource usage due to disabling all concurrency analyses for single-threaded programs, as reported by BenchExec using ordinary least squares (OLS) regression.

The second greatest improvement is due to the use of relational analysis with octagons. Although this incurs a runtime penalty, it increases the number of correct verdicts notably. The improvement is especially visible in NoOverflows, where it yields 104 additional correct results. We also confirmed that the automatic selection of octagon variables is better than tracking all variables: our selection yields more correct verdicts (due to fewer timeouts) while successfully avoiding an unnecessarily large performance penalty.

Autotuning along the other axes is not as impactful. Nevertheless, each leads to Goblint being able to solve tasks it could not otherwise. Hence, a small increase in score is achieved, justifying their use. Although disabling unnecessary concurrency analyses reduces resource usage, overall this performance improvement is canceled out by the simultaneous use of expensive analyses enabled by autotuning, such as octagons. Thus, Goblint can solve more tasks while retaining the same level of overall efficiency observed in previous editions of the competition [3].

Many future opportunities for autotuning exist: Goblint implements a number of concurrent value analyses offering different tradeoffs between time and precision [13, 14], but only used the fastest and least precise of these in SV-COMP. If appropriate heuristics for using the more involved analyses are identified, autotuning could enable these when they are likely to yield a benefit. Autotuning could be extended to supply a sequence of configurations, increasing in precision, for a portfolio of analyses, instead of relying on the autotuning to immediately pick the most appropriate configuration. While the current autotuning in Goblint is hand-crafted, machine learning may provide additional improvements.

4 Tool Setup and Configuration

Goblint version svcomp23-0-g4f5dcf38f participated in SV-COMP 2023 [4, 12]. It is available in both binary (Ubuntu 22.04) and source code form at our GitHub repository under the svcomp23 tag.Footnote 1 The only runtime dependency is Apron [8]. Instructions for building from source can be found in the README.

Both the tool-info module and the benchmark definition for SV-COMP are named goblint. They correspond to running the tool as follows:

figure c

Goblint participated in the following categories: ReachSafety, ConcurrencySafety, NoOverflows, SoftwareSystems and Overall, while opting-out from MemSafety, Termination and SoftwareSystems-*-MemSafety.

5 Software Project and Contributors

Goblint development takes place on GitHub,Footnote 2 while related publications are listed on its website.Footnote 3 It is an MIT-licensed joint project of the Technische Universität München (Chair of Formal Languages, Compiler Construction, Software Construction) and University of Tartu (Laboratory for Software Science).