GOTO-ANALYZER(1)
π GOTO-ANALYZER(1) β User Commands π
okay bestie π welcome to the manual page for goto-analyzer, section 1 (User Commands). this is the over-approximating queen of static analysis and she is literally here to spill all the tea ββ¨. no cap.
πΈ NAME πΈ
goto-analyzer β Data-flow analysis for C programs and goto binaries β¨
π¦ SYNOPSIS π¦
goto-analyzer [-?|-h|--help]
goto-analyzer --version
goto-analyzer [options] file.c|file.gb
goto-analyzer [--no-standard-checks] file.c ...
goto-analyzer [--no-standard-checks] [--pointer-check] file.c ...
goto-analyzer [--no-bounds-check] file.c ...
π DESCRIPTION π
okay so goto-analyzer is an abstract interpreter which uses the same front-end and GOTO binary representation as cbmc(1) π―ββοΈ.
The key difference is that cbmc(1) under-approximates the behavior of the program (execution traces that are too long or require too many loop unwindings are not considered) while goto-analyzer over-approximates the behavior of the program. cbmc(1) can determine if a property is A. true for a bounded number of iterations or B. false and giving an error trace. In contrast goto-analyzer can determine if a property is A. true for all iterations or B. possibly false. In this sense, each tool has its own strengths and weaknesses π
.
To use goto-analyzer you need to give options for:
- What task to perform after the abstract interpreter has run.
- How to format the output.
- Which abstract interpreter is used.
- Which domain is used to describe the state of the program at a point during execution.
- How the history of the control flow of the program determines the number of points of execution.
- The storage that links points of execution and domains.
β¨ OPTIONS β¨
π― Task options:
goto-analyzer first runs the abstract interpreter until it reaches a fix-point, then it will perform the task the user has chosen.
--showβ Displays a domain for every instruction in the GOTO binary. The format and information will depend on the domain that has been selected. If there are multiple domains corresponding to the same location (see history below) these will be merged before they are displayed.--show-on-sourceβ The source code of the program is displayed line-by-line with the abstract domains corresponding to each location displayed between them. As the analysis is done at the level of instructions in the GOTO binary, some domains may not be displayed. Also if parts of the GOTO binary have been generated or manipulated by other tools, these may not be displayed as there is no corresponding source.--show-on-sourceis the more user-friendly output, but--showgives a better picture of exactly what is computed.--verifyβ Every property in the program is checked to see whether it is true (it always holds), unreachable, false if it is reachable (due to the over-approximate analysis, it is not clear if locations are reachable or if it is an overapproximation, so this is the best that can be achieved) or unknown. If there are multiple points of execution that reach the same location, each will be checked and the answers combined, with unknown taking precedence.--simplifyfile_nameβ Writes a new version of the input program tofile_namein which the program has been simplified using information from the abstract interpreter. The exact simplification will depend on the domain that is used but typically this might be replacing any expression that has a constant value. If this makes instructions unreachable (for example if GOTO can be shown to never be taken) they will be removed. Removal can be deactivated by passing--no-simplify-slicing. In the ideal world simplify would be idempotent (i.e. running it a second time would not simplify anything more than the first). However there are edge cases which are difficult or prohibitively expensive to handle in the domain which can result in a second (or more) runs giving simplification. Submitting bug reports for these is helpful but they may not be viable to fix.--no-simplify-slicingβ Do not remove instructions from which no property can be reached (use with--simplify).--unreachable-instructionsβ Lists which instructions have a domain which is bottom (i.e. unreachable). If--functionhas been used to set the program entry point then this can flag things like the main function as unreachable.--unreachable-functionsβ Similar to--unreachable-instructions, but reports which functions are definitely unreachable rather than just instructions.--reachable-functionsβ The negation of--unreachable-functions, reports which functions may be reachable. Note that because the analysis is over-approximate, it is possible this will mark functions as reachable when a more precise analysis (possibly usingcbmc(1)) will show that there are no execution traces that reach them.
π§ Abstract interpreter options:
These options control which abstract interpreter is used and how the analysis is performed. In principle this can significantly change the accuracy and performance of goto-analyzer but the current options are reasonably similar.
If --verbosity is set above 8 the abstract interpreter will log what it is doing. This is intended to aid developers in understanding how the algorithms work, where time is being spent, etc. but can be generally quite instructive.
--legacy-aitβ This is the default option. Abstract interpretation is performed eagerly from the start of the program until fixed-point is reached. Functions are analyzed as needed and in the order of that they are reached. This option also fixes the history and storage options to their defaults.--recursive-interproceduralβ This extends--legacy-aitby allowing the history and storage to be configured. As the name implies, function calls are handled by recursion within the interpreter. This is a good all-round choice and will likely become the default at some point in the future.--three-way-mergeβ This extends--recursive-interproceduralby performing a "modification aware" merge after function calls. At the time of writing only--vsdsupports the necessary differential reasoning. If you are using--vsdthis is recommended as it is more accurate with little extra cost.--legacy-concurrentβ This extends--legacy-aitwith very restricted and special purpose handling of threads. This needs the domain to have certain unusual properties for it to give a correct answer. At the time of writing only--dependence-graphis compatible with it.--location-sensitiveβ Use location-sensitive abstract interpreter.
π°οΈ History options:
To over-approximate what a program does, it is necessary to consider all of the paths of execution through the program. As there are a potentially infinite set of traces (and they can be potentially infinitely long) it is necessary to merge some of them. The common approach (the "collecting abstraction") is to merge all paths that reach the same instruction. The abstract interpretation is then done between instructions without thinking about execution paths. This ensures termination but means that it is not possible to distinguish different call sites, loop iterations or paths through a program.
Note that --legacy-ait, the default abstract interpreter fixes the history to --ahistorical so you will need to choose another abstract interpreter to make use of these options.
--ahistoricalβ This is the default and the coarsest abstraction. No history information is kept, so all traces that reach an instruction are merged. This is the collecting abstraction that is used in most abstract interpreters.--call-stacknβ This is an inter-procedural abstraction; it tracks the call stack and only merges traces that reach the same location and have the same call stack. The effect of this is equivalent to inlining all functions and then using--ahistorical. In larger programs this can be very expensive in terms of both time and memory but can give much more accurate results. Recursive functions create a challenge as the call stack will be different each time. To prevent non-termination, the parameternlimits how many times a loop of recursive functions can be called. Whennis reached all later ones will be merged. Setting this to 0 will disable the limit.--loop-unwindnβ This tracks the backwards jumps that are taken in the current function. Traces that reach the same location are merged if their history of backwards jumps is the same. At mostntraces are kept for each location, after that they are merged regardless of whether their histories match. This gives a similar effect to unrolling the loopsntimes and then using--ahistorical. In the case of nested loops, the behavior can be a little different to unrolling as the limit is the number of times a location is reached, so a loop withxiterations containing a loop withyiterations will requiren=x*y. The time and memory taken by this option will rise (at worst) linearly in terms ofn. Ifnis 0 then there is no limit. Be warned that if there are loops that can execute an unbounded number of iterations or if the domain is not sufficiently precise to identify the termination conditions then the analysis will not terminate.--branchingnβ This works in a similar way to--loop-unwindbut tracking forwards jumps (if, switch, goto, etc.) rather than backwards ones. This gives per-path analysis but limiting the number of times each location is visited. There is not a direct form of program transformation that matches this but it is similar to the per-path analysis that symbolic execution does. The scalability and the risk of non-termination ifnis 0 remain the same. Note that the goto-programs generated by various language front-ends have a conditional forwards jump to exit the loop if the condition fails at the start and an unconditional backwards jump at the end. This means that--branchingcan wind up distinguishing different loop iterations β "has not exited for the last 3 iterations" rather than "has jumped back to the top 3 times".--loop-unwind-and-branching nβ okay so this one is basically--loop-unwindbut it also keeps an eye on jumps going backwards and forwards. Bestie, it's only a tiny bit more expensive than--branchingand honestly? it's probably the best pick if you want to do detailed analysis of each function. slay. π
β¨ Domain options β¨
These control how the possible states at a given execution point are represented and manipulated. (yes, that's the whole vibe β how we store the maybe-states.)
--dependence-graphβ tracks data flow and information flow dependencies between instructions and produces a graph. This includes doing points-to analysis and tracking reaching definitions (i.e. use-def chains). One of the most extensive, correct and feature complete domains. iconic behavior honestly. π--vsd,--variable-sensitivityβ this is the Variable Sensitivity Domain (VSD). It's a non-relational domain that stores an abstract object for each live variable. Which kind of abstract objects get used depends on the type of the variable and the run-time configuration. Which means the sensitivity of the domain can be chosen β like, do you wanna track every element of an array independently, or just a few of them, or simply ignore arrays all together? A set of options to configure VSD are given below. This domain is extensive and does not have any known architectural limits on correctness. So it's a good choice for many kinds of analysis. π«Ά--dependence-graph-vsβ a variant of the dependence graph domain that uses VSD to do the foundational pointer and reaching definitions analysis. So you can configure it with the VSD options and get more precise analysis (for example, field aware) of the dependencies. β¨--constantsβ the default option, this stores one constant value per variable. So it's fast but it will only find things that can be resolved by constant propagation. The domain has some handling of arrays but limited support for pointers which means it can potentially give unsound behavior.--vsd --vsd-values constantsis probably a better choice for this kind of analysis. π--intervalsβ a domain that stores an interval for each integer and float variable. At the time of writing not all operations are supported so the results can be quite over-approximate at points. It also has limitations in the handling of pointers so it can give unsound results.--vsd --vsd-values intervalsis probably a better choice for this kind of analysis.--non-nullβ this domain is intended to find which pointers are not null. Its implementation is very limited and it is not recommended. π (read that again, bestie.)
πΈ Variable sensitivity domain (VSD) options πΈ
VSD has a wide range of options that let you choose what kind of abstract objects (and thus abstractions) are used to represent variables of each type. so many knobs. so much power.
--vsd-values [constants|intervals|set-of-constants]β this controls the abstraction used for values, both int and float.- The default option is
constantswhich tracks if the variable has a constant value. This is fast but not very precise so it may well be unable to prove very much. intervalsuses an interval that contains all of the possible values the variable can take. It is more precise thanconstantsin all cases but a bit slower. It is good for numerical code.set-of-constantsuses a set of up to 10 (currently fixed) constants. This is more general than using a single constant but can make analysis up to 10 times (or in rare cases 100 times) slower. It is good for control code with flags and modes.
- The default option is
--vsd-structs [top-bottom|every-field]β this controls how structures are handled. The default istop-bottomwhich uses an abstract object with just two states (top and bottom). In effect writes to structures are ignored and reads from them will always return top (any value). The other alternative isevery-fieldwhich stores an abstract object for each field. Depending on how many structures are live at any one time and how many fields they have this may increase the amount of memory used bygoto-analyzerby a reasonable amount. But this means that the analysis will be field-sensitive. π§--vsd-arrays [top-bottom|smash|up-to-n-elements|every-element]β this controls how arrays are handled.- As with structures, the default is
top-bottomwhich effectively ignores writes to the array and returns top on a read. - More precise than this is
smashwhich stores one abstract element for all of the values. This is relatively cheap but a lot more precise, particularly if used withintervalsorset-of-constants. up-to-n-elementsgeneralizessmashby storing abstract objects for the first n elements of each array (n defaults to 10 and can be controlled by--vsd-array-max-elements) and then condensing all other elements down to a single abstract object. This allows reasonably fine-grained control over the amount of memory used and can give much more precise results for small arrays.every-elementis the most precise, but most expensive option where an abstract element is stored for every entry in the array. πΈ
- As with structures, the default is
--vsd-array-max-elementsβ configures the value of n in--vsd-arrays up-to-n-elementsand defaults to10if not given.--vsd-pointers [top-bottom|constants|value-set]β this controls the handling of pointers.- The default,
top-bottom, effectively ignores pointers. This is OK if they are just read (all reads return top) but if they are written then there is the problem that we know that a variable is changed but we don't know which one, so we have to set the whole domain to top. π constantsis somewhat misleadingly named as it uses an abstract object that tracks a pointer to a single variable. This includes the offset within the variable; a stack of field names for structs and abstract objects for offsets in arrays. Offsets are tracked even if the abstract object for the variable itself does not distinguish different fields or indexes.value-setis the most precise option; it stores a set of pointers to single variables as described above.
- The default,
--vsd-unions top-bottomβ at the time of writing there is only one option for unions which istop-bottom, discarding writes and returning top for all reads from a variable of union type.--vsd-data-dependenciesβ wraps each abstract object with a set of locations where the variable was last modified. The set is reset when the variable is written and takes the union of the two sides' sets on merge. This was originally intended for--dependence-graph-vsbut has proved useful for--vsdas well. This is not strictly necessary for--three-way-mergeas the mechanism it uses to work out which variables have changed is independent of this option.--vsd-livenessβ wraps each abstract object with the location of the last assignment or merge. This is more basic and limited than--vsd-data-dependenciesand is intended to track SSA-like regions of variable liveness.--vsd-flow-insensitiveβ this does not alter the abstract objects used or their configuration. It disables the reduction of the domain when a branch is taken or an assumption is reached. This normally gives a small saving in time but at the cost of a large amount of precision. This is why the default is to do the reduction. It can be useful for debugging issues with the reduction. π
π Storage options π
The histories described above are used to keep track of where in the computation needs to be explored. The most precise option is to keep one domain for every history but in some cases, to save memory and time, it may be desirable to share domains between histories. The storage options allow this kind of sharing. sharing is caring fr fr.
--one-domain-per-locationβ this is the default option. All histories that reach the same location will use the same domain. Setting this means that the results of other histories will be similar to setting--ahistorical. One difference is how and when widening occurs:--one-domain-per-location --loop-unwind nwill wait until n iterations of a loop have been completed and then will start to widen.--one-domain-per-historyβ this is the best option to use if you are using a history other than--ahistorical. It stores one domain per history which can result in a significant increase in the amount of memory used. π«
π Output options π
These options control how the result of the task is output. The default is text to the standard output. In the case of tasks that produce goto-programs (--simplify for example), the output options only affect the logging and not the final form of the program. important distinction bestie!!
--text file_nameβ output results in plain text to given file.--json file_nameβ writes the output as a JSON object to file_name.--xml file_nameβ output results in XML format to file_name.--dot file_nameβ writes the output indot(1)format to file_name. This is only supported by some domains and tasks (for example--show --dependence-graph).
β Specific analyses β
--taint file_nameβ perform taint analysis using rules in given file.--show-taintβ print taint analysis results on stdout.--show-local-bitvectorβ perform procedure-local bitvector analysis.--show-local-may-aliasβ perform procedure-local may alias analysis.
π C/C++ frontend options π
-I pathβ set include path (C/C++).--include fileβ set include file (C/C++).-D macroβ define preprocessor macro (C/C++).--c89,--c99,--c11,--c17,--c23β set C language standard (default:c11).--cpp98,--cpp03,--cpp11β set C++ language standard (default:cpp98).--unsigned-charβ make"char"unsigned by default.--round-to-nearest,--round-to-evenβ rounding towards nearest even (default).--round-to-plus-infβ rounding towards plus infinity.--round-to-minus-infβ rounding towards minus infinity.--round-to-zeroβ rounding towards zero.--no-libraryβ disable built-in abstract C library.--function nameβ set main function name.
π» Platform options π»
--archarch β Set analysis architecture, which defaults to the host architecture. Use one of:alpha,arm,arm64,armel,armhf,hppa,i386,ia64,mips,mips64,mips64el,mipsel,mipsn32,mipsn32el,powerpc,ppc64,ppc64le,riscv64,s390,s390x,sh4,sparc,sparc64,v850,x32,x86_64, ornone. No cap, that's the whole list.--osos β Set analysis operating system, which defaults to the host operating system. Use one of:freebsd,linux,macos,netbsd,openbsd,solaris,hurd, orwindows. Pick your fighter.--i386-linux,--i386-win32,--i386-macos,--ppc-macos,--win32,--winx64β Set analysis architecture and operating system. Two birds, one iconic flag.--LP64,--ILP64,--LLP64,--ILP32,--LP32β Set width ofint,longand pointers, but don't override default architecture and operating system. Respect the defaults, bestie.--16,--32,--64β Equivalent to--LP32,--ILP32,--LP64(on Windows:--LLP64). Math but make it fashion.--little-endianβ allow little-endian word-byte conversions tiny endian energy--big-endianβ allow big-endian word-byte conversions big endian energy--gccβ useGCCas preprocessor preprocessing slay
π§ Program representations π§
--show-parse-treeβ show parse tree the tree is tree-ing--show-symbol-tableβ show loaded symbol table symbols on symbols--show-goto-functionsβ show loaded goto program goto but make it visible--list-goto-functionsβ list loaded goto functions just a lil list, nbd--show-propertiesβ show the properties, but don't run analysis peek, don't touch
π οΈ Program instrumentation options π οΈ
--no-standard-checksβ disable the standard (default) checks applied to a C/GOTO program (see below for more information) chaos mode: activated--propertyid β enable selected properties only choose your own adventure--bounds-checkβ enable array bounds checks bounds? checked.--pointer-checkβ enable pointer checks pointers, but safe--memory-leak-checkβ enable memory leak checks no drips allowed--memory-cleanup-checkβ Enable memory cleanup checks: assert that all dynamically allocated memory is explicitly freed before terminating the program. clean up your room, bestie--div-by-zero-checkβ enable division by zero checks for integer division no dividing by zero, periodt--float-div-by-zero-checkβ enable division by zero checks for floating-point division floaties can't escape either--signed-overflow-checkβ enable signed arithmetic over- and underflow checks signed, sealed, checked--unsigned-overflow-checkβ enable arithmetic over- and underflow checks unsigned too, we don't discriminate--pointer-overflow-checkβ enable pointer arithmetic over- and underflow checks pointer math? monitored.--conversion-checkβ check whether values can be represented after type cast can you even fit in that type?--undefined-shift-checkβ check shift greater than bit-width shifting too hard--float-overflow-checkβ check floating-point for +/-Inf infinity check, iconic--nan-checkβ check floating-point for NaN not a number? caught.--enum-range-checkβ checks that all enum type expressions have values in the enum range enums staying in their lane--pointer-primitive-checkβ checks that all pointers in pointer primitives are valid or null valid or null, no in-between--retain-trivial-checksβ include checks that are trivially true yes, even the obvious ones--error-labellabel β check that label is unreachable is this label even reachable? vibe check--no-built-in-assertionsβ ignore assertions in built-in library built-in? ignored.--no-assertionsβ ignore user assertions user assertions? not today--no-assumptionsβ ignore user assumptions assumptions? dropped.--assert-to-assumeβ convert user assertions to assumptions glow-up: assertion to assumption--malloc-may-failβ allowmalloccalls to return a null pointer malloc can flop, and that's okay--malloc-fail-assertβ setmallocfailure mode to assert-then-assume assert first, assume later--malloc-fail-nullβ setmallocfailure mode to return null just return null, it's fine--string-abstractionβ track C string lengths and zero-termination strings getting tracked fr fr--dfcc-debug-libβ enable debug assertions in the cprover contracts library debugging the contracts library--dfcc-simple-invalid-pointer-modelβ use simplified invalid pointer model in the cprover contracts library (faster, unsound) faster but unsound β be aware, bestie
π Standard Checks π
Okay so from version 6.0 onwards, cbmc, goto-analyzer and some other tools apply some checks to the program by default β they call them the "standard checks" β with the aim to provide a better user experience for a non-expert user of the tool. These checks are:
--pointer-checkβ enable pointer checks pointers, checked--bounds-checkβ enable array bounds checks bounds, checked--undefined-shift-checkβ check shift greater than bit-width shift, checked--div-by-zero-checkβ enable division by zero checks zero division, checked--pointer-primitive-checkβ checks that all pointers in pointer primitives are valid or null pointer primitives, checked--signed-overflow-checkβ enable signed arithmetic over- and underflow checks signed overflow, checked--malloc-may-failβ allowmalloccalls to return a null pointer malloc may fail, allowed--malloc-fail-nullβ setmallocfailure mode to return null malloc fail mode: null--unwinding-assertions(cbmc-only) β generate unwinding assertions (cannot be used with--cover) cbmc-only, no cover
These checks can all be deactivated at once by using the --no-standard-checks flag like in the header example, or individually, by prepending a no- before the flag, like so:
--no-pointer-checkβ disable pointer checks pointer checks off--no-bounds-checkβ disable array bounds checks bounds checks off--no-undefined-shift-checkβ do not perform check for shift greater than bit-width shift check off--no-div-by-zero-checkβ disable division by zero checks div by zero check off--no-pointer-primitive-checkβ do not check that all pointers in pointer primitives are valid or null pointer primitive check off--no-signed-overflow-checkβ disable signed arithmetic over- and underflow checks signed overflow check off--no-malloc-may-failβ do not allowmalloccalls to fail by default malloc may fail: disabled--no-unwinding-assertions(cbmc-only) β do not generate unwinding assertions (cannot be used with--cover) cbmc-only, no cover
If an already set flag is re-set, like calling --pointer-check when default checks are already on, the flag is simply ignored. No drama, it just shrugs.
π Other options π
--validate-goto-modelβ enable additional well-formedness checks on the goto program goto model, validated--validate-ssa-equationβ enable additional well-formedness checks on the SSA representation SSA, validated--versionβ show version and exit version check, then bye--flushβ flush every line of output flush it, bestie--verbosity# β verbosity level how loud do you want it?--timestamp[monotonic|wall]β Print microsecond-precision timestamps.monotonic: stamps increase monotonically.wall: ISO-8601 wall clock timestamps. timestamps, but make it precise
π ENVIRONMENT π
All tools honor the TMPDIR environment variable when generating temporary files and directories. Respect the TMPDIR, bestie.
π BUGS π
If you encounter a problem please create an issue at https://github.com/diffblue/cbmc/issues the devs are iconic and will help, iykyk
π SEE ALSO π
cbmc(1), goto-cc(1) β go check them out, fr fr. obsessed with cross-references.
π COPYRIGHT π
2017-2018, Daniel Kroening, Diffblue periodt. π
That's the tea, bestie. This was goto-analyzer-5.59.0, dated June 2022, and it's GOTO-ANALYZER(1). Stay slaying! πβ¨
π¦ where this page comes from
- debian trixie: cbmc 6.6.0-4 Β· BSD-4-Clause
- fedora 43: cbmc 6.7.1-2.fc43 Β· BSD-4-Clause
- fedora 44: cbmc 6.8.0-1.fc44 Β· BSD-4-Clause
- nixos 26.05: cbmc 6.9.0
- nixpkgs unstable: cbmc 6.11.0
- ubuntu questing: cbmc 6.6.0-4
- ubuntu resolute: cbmc 6.6.0-4ubuntu2 Β· BSD-4-Clause
- ubuntu stonking: cbmc 6.6.0-4ubuntu2 Β· BSD-4-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms