On this page:
15.1 Invoking Boogie
15.1.1 Usage
15.1.2 Option syntax
15.1.3 Unknown options behave differently on Unix
15.1.4 Input files
15.1.5 Exit codes
15.2 Informational options
15.3 Selecting what to verify
15.3.1 /  proc and /  no  Proc
15.3.2 /  verify  Separately
15.3.3 /  no  Resolve, /  no  Typecheck, /  no  Verify
15.3.4 /  overlook  Type  Errors
15.4 Libraries
15.5 Printing the program
15.5.1 /  print and the print modifiers
15.5.2 /  print  Passive
15.5.3 /  print  Split, /  print  Pruned and /  print  Split  Declarations
15.5.4 /  print  Instrumented and /  print  Inlined
15.5.5 /  print  CFG
15.5.6 /  print  Lean
15.5.7 /  xml
15.5.8 File-name macros and /  log  Prefix
15.5.9 /  use  Base  Name  For  File  Name and /  print  Verified  Procedures  Count
15.6 Verification-condition generation
15.6.1 Program transformations before VC generation
15.6.2 /  subsumption
15.6.3 /  always  Assume  Free  Loop  Invariants
15.6.4 /  prune
15.6.5 Type and array encoding
15.6.6 Prover-input stability
15.6.7 /  keep  Quantifier and pool instantiation
15.7 Error reporting
15.7.1 /  error  Limit
15.7.2 /  error  Trace
15.7.3 /  print  Model, /  print  Model  To  File and /  mv
15.7.4 /  enhanced  Error  Messages
15.7.5 /  force  Bpl  Errors
15.7.6 /  track  Verification  Coverage and /  warn  Vacuous  Proofs
15.7.7 /  smoke and /  smoke  Timeout
15.8 Resource limits
15.8.1 How a timeout is reported
15.8.2 /  run  Diagnostics  On  Timeout and /  trace  Diagnostics  On  Timeout
15.9 Prover selection and options
15.9.1 /  prover  Dll
15.9.2 /  prover  Opt (/  p)
15.9.3 /  prover  Log, /  prover  Log  Append and /  prover  Preamble
15.9.4 Other prover-facing options
15.10 Splitting and parallelism
15.10.1 /  vcs  Max  Cost
15.10.2 The splitting cost model
15.10.3 /  vcs  Split  On  Every  Assert and /  vcs  Dump  Splits
15.10.4 /  vcs  Cores and /  vcs  Load
15.10.5 /  relax  Focus
15.11 Inference
15.11.1 Abstract interpretation:   /  infer
15.11.2 Houdini:   /  contract  Infer
15.11.3 Staged and concurrent Houdini
15.12 Inlining and loops
15.12.1 /  inline and /  print  Inlined
15.12.2 Loop options
15.12.3 Stratified inlining
15.12.4 Lambda-lifting options
15.12.5 /  print  Measure  Desugaring
15.13 Caching and snapshots
15.13.1 /  verify  Snapshots
15.13.2 /  trace  Caching
15.14 Civl
15.15 Verbosity, tracing and debugging
15.15.1 Verbosity levels
15.15.2 /  trace and friends
15.16 Options with no effect, and undocumented options
15.16.1 Options with no effect
15.16.2 Undocumented options
15.17 Complete option index
8.17

15 Command-line reference🔗

This chapter documents every option the boogie executable accepts. The authority is the source, not the built-in help text:

This is Boogie 2 says nothing about the command line. The 2008 paper describes the language and its semantics; the tool’s option surface is not mentioned anywhere in it. Everything in this chapter comes from the implementation.

Examples in this chapter are run as boogie; the solver is Z3 5.0.0. Where an example’s output contains a // Command Line Options: banner it has been produced with /env:0 so that the banner is suppressed.

15.1 Invoking Boogie🔗

15.1.1 Usage🔗

boogie [ option ... ] [ filename ... ]

Arguments that do not begin with / or - are input files. Options and files may be interleaved freely; all files named on the command line are parsed and concatenated into a single Boogie program before resolution, unless /verifySeparately is given.

15.1.2 Option syntax🔗

An argument is treated as an option if it starts with / or -. Both prefixes are accepted for every option: /trace and -trace are the same switch. Option names are case-sensitive.

An option that takes one argument accepts it in either of two forms:

boogie /proc Abs cli-abs.bpl

 

Boogie program verifier finished with 1 verified, 0 errors

The separate form is a trap for options whose argument is optional-looking. /prune takes an integer argument, so boogie /prune file.bpl tries to parse file.bpl as an integer and fails.

Boolean flags take no argument, and attaching one is an error rather than being ignored:

boogie /trace:1 cli-small.bpl

Boogie: Error: "/trace" cannot take a colon argument

Use /help for available options

Argument validation errors all take the same shape and stop the run before any file is read:

boogie /errorLimit

boogie /errorLimit cli-small.bpl

boogie /errorLimit:abc cli-small.bpl

boogie /errorLimit:-1 cli-small.bpl

Boogie: Error: "/errorLimit" expects 1 argument

Use /help for available options

Boogie: Error: Invalid argument "cli-small.bpl" to option /errorLimit

Use /help for available options

Boogie: Error: Invalid argument "abc" to option /errorLimit

Use /help for available options

Boogie: Error: Invalid argument "-1" to option /errorLimit

Use /help for available options

Note the second line: in the separate form the option swallowed the file name.

Integer arguments are read with Convert.ToInt32 and by default must be non-negative; several options add a stricter upper bound (for example /errorTrace requires 0 <= n < 3). Unsigned arguments use Convert.ToUInt32. Double arguments use Convert.ToDouble with the invariant culture and must be non-negative.

15.1.3 Unknown options behave differently on Unix🔗

CommandLineOptionEngine.Parse contains a platform test: when Path.DirectorySeparatorChar is / that is, on Linux and macOS — an unrecognised option that begins with / is silently reclassified as a file name, on the theory that it might be an absolute path. Only the - form produces an "unknown switch" diagnostic:

boogie /notAnOption cli-abs.bpl

*** Error: '/notAnOption': Filename extension '' is not supported. Input files must be BoogiePL programs (.bpl).

boogie -notAnOption cli-abs.bpl

Boogie: Error: unknown switch: -notAnOption

Use /help for available options

Both exit with status 1. On Unix, prefer - when you want typos to be reported as typos.

15.1.4 Input files🔗

BoogieDriver.GetFileList applies two rules before anything is parsed:

echo 'cli-f1.bpl cli-f2.bpl' > files.txt

boogie files.txt

cli-f2.bpl(1,17): Error: this assertion could not be proved

Execution trace:

    cli-f2.bpl(1,17): anon0

 

Boogie program verifier finished with 1 verified, 1 error

The file named stdin.bpl is special to the parser (Parser.Parse reads standard input for it), not to the driver: see Lexical structure.

15.1.5 Exit codes🔗

Boogie’s exit code is not a verification verdict. Main returns 0 unless one of a small number of conditions holds:

Situation

  

Exit code

Command-line parse error

  

1

No input files

  

1

Input file with an extension other than .bpl

  

1

A ProverException during verification (bad /proverOpt, solver binary not found, ...)

  

1

Cancellation by /processTimeLimit

  

1

Parse errors in a .bpl file

  

0

Name-resolution errors

  

0

Type-checking errors

  

0

Monomorphisation failure (Unable to monomorphize input program: ...)

  

0

Verification errors, timeouts, out-of-resource, inconclusive

  

0

Success

  

0

boogie cli-abs.bpl ; echo "exit=$?"

cli-abs.bpl(11,1): Error: a postcondition could not be proved on this return path

cli-abs.bpl(8,3): Related location: this is the postcondition that could not be proved

Execution trace:

    cli-abs.bpl(10,5): anon0

 

Boogie program verifier finished with 1 verified, 1 error

exit=0

Scripts must therefore inspect the output text (or the /xml file), not $?. Boogie’s own test suite does exactly this: its lit tests diff the output against a .expect file.

15.2 Informational options🔗

These are handled by ProcessInfoFlags, which runs after argument parsing and before any file is read. If more than one is given, the first match in the order /version, /help, /attrHelp, /proverHelp wins, the rest are ignored, input files are not touched, and the process exits 0.

Option

  

Effect

/version

  

Print "Boogie program verifier version v, Copyright (c) 2003-2014, Microsoft." The version is the assembly FileVersion.

/help

  

Print the usage message. /? is an accepted synonym and is itself undocumented.

/attrHelp

  

Print the list of supported declaration attributes (CommandLineOptions.AttributeHelp). This is the only place many attributes are documented in the tool.

/proverHelp

  

Print the options accepted by /proverOpt for the selected prover back end. ProverHelp is TheProverFactory.BlankProverOptions(this).Help and is evaluated inside ProcessInfoFlags, after the whole command line has been parsed, so a /proverDll on either side of /proverHelp takes effect. In practice there is no other back end to ask — see Prover selection and options.

Three more options are informational in spirit:

Option

  

Argument

  

Default

  

Effect

/env:n

  

0, 1 or 2

  

1

  

Where to echo the command line. 0 = never; 1 = in the two-line banner of whatever PrintBplFile writes (/print, /civlDesugaredFile); 2 = also to standard output, one argument per line, before verification starts. Those are the only two readers of ShowEnv in the source — prover logs never carry the banner, and neither does /printPassive.

/wait

  

none

  

off

  

Print "Press Enter to exit." and block on standard input just before the process exits.

/break, /launch

  

none

  

off

  

Call System.Diagnostics.Debugger.Launch() at the point the option is parsed. /launch is an undocumented synonym. With no debugger registered this is a no-op on Linux.

boogie /env:2 /noVerify cli-small.bpl

---Command arguments

/env:2

/noVerify

cli-small.bpl

--------------------

 

Boogie program verifier finished with 0 verified, 0 errors

15.3 Selecting what to verify🔗

15.3.1 /proc and /noProc🔗

Option

  

Argument

  

Default

/proc:p

  

glob pattern; repeatable

  

empty (check everything)

/noProc:p

  

glob pattern; repeatable

  

empty

Both accumulate into lists. ExecutionEngineOptions.UserWantsToCheckRoutine decides:

procedure Abs(x: int) returns (r: int)

  ensures 0 <= r;

{

  if (x < 0) { r := -x; } else { r := x; }

}

 

procedure Bad(x: int) returns (r: int)

  ensures 0 < r;

{

  r := x;

}

boogie /proc:Abs cli-abs.bpl

 

Boogie program verifier finished with 1 verified, 0 errors

Case matters — *a* matches Bad but not Abs:

boogie '/proc:*a*' cli-abs.bpl

cli-abs.bpl(11,1): Error: a postcondition could not be proved on this return path

cli-abs.bpl(8,3): Related location: this is the postcondition that could not be proved

Execution trace:

    cli-abs.bpl(10,5): anon0

 

Boogie program verifier finished with 0 verified, 1 error

boogie /noProc:Bad cli-abs.bpl

 

Boogie program verifier finished with 1 verified, 0 errors

Filtered-out implementations are neither verified nor inlined, but they are still parsed, resolved and type-checked, and they still contribute declarations to the program.

{:verboseName} changes both the name /proc matches and the name printed by /trace:

procedure {:verboseName "My Nice Name"} P()

{

  assert true;

}

boogie /trace cli-verbosename.bpl

Parsing cli-verbosename.bpl

Coalescing blocks...

Inlining...

 

Verifying My Nice Name ...

[TRACE] Using prover: z3

  [0.027 s, solver resource count: 98, 1 proof obligation]  verified

 

Boogie program verifier finished with 1 verified, 0 errors

15.3.2 /verifySeparately🔗

/verifySeparately (boolean, off by default) has an effect only when more than one file is named. Each file is then processed as its own program, from parsing through the trailer, and the overall result is the conjunction of the per-file results. Everything is reported once per file:

cli-f1.bpl and cli-f3.bpl both declare procedure A.

boogie /verifySeparately cli-f1.bpl cli-f3.bpl

 

Boogie program verifier finished with 1 verified, 0 errors

 

Boogie program verifier finished with 1 verified, 0 errors

Because the files never share a resolution scope, duplicate declarations across files stop being errors. Without the flag the same two files fail to resolve:

boogie cli-f1.bpl cli-f3.bpl

cli-f3.bpl(1,10): Error: more than one declaration of procedure name: A

1 name resolution errors detected in cli-f3.bpl

/verifySeparately also passes each file name as the program id used for result caching, so it composes with /verifySnapshots.

15.3.3 /noResolve, /noTypecheck, /noVerify🔗

Option

  

Stops after

/noResolve

  

parsing

/noTypecheck

  

parsing and name resolution

/noVerify

  

everything except VC generation and the prover

All three are boolean flags, all off by default.

/noResolve and /noTypecheck return PipelineOutcome.Done from ResolveAndTypecheck, and ProcessProgram then returns without writing a trailer. The consequence is that these two options produce no output at all on success — not even the "finished with" line:

boogie /noResolve cli-small.bpl ; echo "exit=$?"

exit=0

/noVerify stops later, after Civl rewriting, inlining and dead-variable elimination, and does print a trailer:

boogie /noVerify cli-abs.bpl

 

Boogie program verifier finished with 0 verified, 0 errors

/noVerify is the usual companion to the printing options in Printing the program: /print runs before verification, so you rarely want to pay for the prover as well.

15.3.4 /overlookTypeErrors🔗

Boolean, off by default. It applies to resolution errors. The single site that reads OverlookBoogieTypeErrors is in Program.Resolve: if resolving a top-level declaration raised errors and that declaration is an Implementation, the errors are rolled back and the implementation is dropped. Type checking runs afterwards and is unaffected.

procedure Good()

{

  assert true;

}

 

procedure Bad2()

{

  assert undeclaredThing;

}

boogie /overlookTypeErrors cli-overlook.bpl

cli-overlook.bpl(8,9): Error: undeclared identifier: undeclaredThing

Warning: Ignoring implementation Bad2 because of translation resolution errors

 

Boogie program verifier finished with 1 verified, 0 errors

Replace the body with a genuine type error (assert 1 + true;) and the option makes no difference: the run still ends with 1 type checking errors detected.

15.4 Libraries🔗

Option

  

Argument

  

Default

/lib:name

  

library name; repeatable

  

none

/lib:name loads name.bpl as an embedded resource named Core.name.bpl from Boogie.Core.dll and appends its declarations to the program after all command-line files have been parsed. The libraries actually embedded (see Source/Core/Core.csproj) are:

Name

  

Contents

base

  

323 lines: the Set, Map and Vec operations, the Option and Vec datatypes, One, Loc, Default, Identity, MapConst/MapIte

node

  

146 lines: the Node datatype with Between and Avoiding reachability predicates; built on base

set_size

  

29 lines: Set_Size and its cardinality axioms and lemmas; built on base

The help text lists only base and node; set_size is undocumented.

boogie /lib:base cli-lib.bpl

 

Boogie program verifier finished with 1 verified, 0 errors

Two things surprise people:

Libraries is a HashSet<string>, so repeating /lib:base is harmless but the order in which libraries are appended is not the order you wrote them.

Finally, ParseBoogieProgram adds base automatically whenever any top-level declaration carries a Civl attribute, and at the same time forces InferModifies on. A Civl program therefore never needs /lib:base or /inferModifies spelled out.

15.5 Printing the program🔗

15.5.1 /print and the print modifiers🔗

Option

  

Argument

  

Default

/print:file

  

file name, or - for the console

  

off

/pretty:n

  

0 or 1

  

1

/printWithUniqueIds

  

none

  

off

/printUnstructured

  

none

  

off

/printDesugared

  

none

  

off

/printLambdaLifting

  

none

  

off

/printMeasureDesugaring

  

none

  

off

/print by itself emits the program immediately after parsing before resolution, type checking, Civl rewriting or inlining. The file name - means the console, and the name may use the macros described in File-name macros and /logPrefix. Unless /env:0 is given, two comment lines precede the program:

boogie /print:- /noVerify cli-small.bpl

// Boogie program verifier version 3.5.7.0, Copyright (c) 2003-2014, Microsoft.

// Command Line Options: /print:- /noVerify cli-small.bpl

 

procedure Abs(x: int) returns (r: int);

  ensures 0 <= r;

 

 

 

implementation Abs(x: int) returns (r: int)

{

    if (x < 0)

    {

        r := -x;

    }

    else

    {

        r := x;

    }

}

 

 

 

Boogie program verifier finished with 0 verified, 0 errors

Note that a procedure with a body is printed as a procedure declaration followed by a separate implementation, which is exactly how the parser represents it.

The modifiers change what is printed and, for three of them, when:

Modifier

  

Printed at

/printUnstructured

  

same place as /print (formatting only)

/printWithUniqueIds

  

same place as /print (formatting only)

/printDesugared

  

additionally after resolution and type checking

/printMeasureDesugaring

  

additionally after measure desugaring

/printLambdaLifting

  

additionally after lambda lifting, inside InferAndVerify

Because the last three add a printing point rather than moving it, the program is written out twice. So /print:out.bpl /printDesugared leaves only the second copy in out.bpl while /print:- /printDesugared shows both on the console.

/printUnstructured desugars structured statements into a goto graph while keeping the structured form in a comment:

boogie /print:- /noVerify /env:0 /printUnstructured cli-small.bpl

 

procedure Abs(x: int) returns (r: int);

  ensures 0 <= r;

 

 

 

implementation Abs(x: int) returns (r: int)

{

  /*** structured program:

    if (x < 0)

    {

        r := -x;

    }

    else

    {

        r := x;

    }

  **** end structured program */

 

  anon0:

    goto anon3_Then, anon3_Else;

 

  anon3_Then:

    assume {:partition} x < 0;

    r := -x;

    return;

 

  anon3_Else:

    assume {:partition} 0 <= x;

    r := x;

    return;

}

 

 

 

Boogie program verifier finished with 0 verified, 0 errors

Internally PrintUnstructured is a three-valued field: 0 = structured only, 1 = both (what the flag sets), 2 = unstructured only. The flag can only reach 0 and 1. The only place in the source that sets 2 is the /printPassive writer, which is why the passive program printed below (/printPassive) carries no /*** structured program comment. /civlDesugaredFile and /printMeasureDesugaring set the field to 1, not 2, so their output still repeats the structured form in a comment.

/printDesugared expands calls into their assert/havoc/assume encoding, as a comment attached to the original call. Only the relevant part of the second copy is shown:

boogie /print:- /noVerify /env:0 /printDesugared cli-call.bpl

implementation Q()

{

  var a: int;

 

    call a := P(3);

    /*** desugaring:

    {

      var call0formal#AT#x: int;

      var call1old#AT#g: int;

      var call2formal#AT#y: int;

      call0formal#AT#x := 3;

      assert 0 <= call0formal#AT#x;

      call1old#AT#g := g;

      havoc g, call2formal#AT#y;

      assume call2formal#AT#y == call0formal#AT#x;

      a := call2formal#AT#y;

    }

    **** end desugaring */

    assert a == 3;

}

/printWithUniqueIds prefixes each identifier with the unique id of its declaration. Because /print runs before resolution, the ids are usually all NoDecl:

if (NoDecl^^x < 0)

{

    NoDecl^^r := -NoDecl^^x;

}

Combine it with /printDesugared (which prints after resolution) to get real ids.

/pretty:0 turns off the line-breaking pass in TokenTextWriter. The difference only shows up when a sub-expression’s rendering exceeds 80 characters:

procedure Big(aaaaaaaaaa: int, bbbbbbbbbb: int, cccccccccc: int, dddddddddd: int)

{

  assert aaaaaaaaaa < bbbbbbbbbb && bbbbbbbbbb < cccccccccc && cccccccccc < dddddddddd ==> aaaaaaaaaa < dddddddddd;

}

assert aaaaaaaaaa < bbbbbbbbbb && bbbbbbbbbb < cccccccccc && cccccccccc < dddddddddd

   ==> aaaaaaaaaa < dddddddddd;

versus, with /pretty:0:

assert aaaaaaaaaa < bbbbbbbbbb && bbbbbbbbbb < cccccccccc && cccccccccc < dddddddddd ==> aaaaaaaaaa < dddddddddd;

15.5.2 /printPassive🔗

Option

  

Argument

  

Default

/printPassive:file

  

file name

  

off

/printPassive requires a file name, writes the passified program to that file directly, and is independent of /print. Because it takes an argument, giving it without one consumes the input file name (Invoking Boogie):

boogie /printPassive cli-small.bpl

*** Error: No input files were specified.

Given a file name it writes the fully passive (single-assignment, goto-only) program, at the point in VerificationConditionGenerator where passification finishes:

boogie /printPassive:passive.out cli-small.bpl > /dev/null ; cat passive.out

 

procedure Abs(x: int) returns (r: int);

  ensures 0 <= r;

 

 

 

implementation Abs(x: int) returns (r: int)

{

  var r#AT#0: int;

  var r#AT#1: int;

 

 

  anon0:

    goto anon3_Then, anon3_Else;

 

  anon3_Else:

    assume {:partition} 0 <= x;

    assume r#AT#1 == x;

    goto GeneratedUnifiedExit;

 

  GeneratedUnifiedExit:

    assert 0 <= r#AT#1;

    return;

 

  anon3_Then:

    assume {:partition} x < 0;

    assume r#AT#0 == -x;

    assume r#AT#1 == r#AT#0;

    goto GeneratedUnifiedExit;

}

Note there is no /env banner: this writer is created directly and does not emit one. Note also that the file is rewritten from scratch every time an implementation is passified, and each write emits the whole program. The file you are left with is therefore the state of the program at the last write: with /vcsCores:1 that means every implementation appears, in passive form.

15.5.3 /printSplit, /printPruned and /printSplitDeclarations🔗

Option

  

Argument

  

Default

/printSplit:prefix

  

path prefix, or - for the console

  

off

/printPruned:prefix

  

same --- exact synonym

  

off

/printSplitDeclarations

  

none

  

off

/printSplit and /printPruned share a case label and set the same field; only /printPruned is documented. Each VC split is written to prefix-name.spl, where name is the implementation name plus a suffix identifying the split, escaped for use in a file name. With - the splits go to the console (with a 100 ms sleep before each, to keep concurrent writers from interleaving).

mkdir -p sp

boogie /printSplit:sp/x cli-abs.bpl > /dev/null ; ls sp/

x-Abs--1.spl

x-Bad--1.spl

Boogie does not create the directory. If it does not exist the writer throws and the implementation is abandoned (the absolute paths have been shortened here):

boogie /printSplit:nosuchdir/x cli-abs.bpl

Advisory: Abs SKIPPED due to I/O exception: Could not find a part of the path '.../nosuchdir/x-Abs--1.spl'.

cli-abs.bpl(1,11): Verification encountered solver exception (Abs)

Advisory: Bad SKIPPED due to I/O exception: Could not find a part of the path '.../nosuchdir/x-Bad--1.spl'.

cli-abs.bpl(7,11): Verification encountered solver exception (Bad)

 

Boogie program verifier finished with 0 verified, 0 errors, 2 solver exceptions

The 1 suffix is "-" + SplitIndex + Token.ShortName with SplitIndex of -1; when {:focus} or {:split_here} produce manual splits the suffix becomes informative, for example Ex-2/focus[+16,-20,+25].

/printSplitDeclarations additionally appends the declarations that survived pruning for that split. It is silently ignored unless pruning is on (Split.PrintSplitDeclarations returns immediately when !Options.Prune), which makes it a convenient probe for what /prune keeps — see /prune.

15.5.4 /printInstrumented and /printInlined🔗

/printInstrumented (boolean, off) prints the program after abstract-interpretation results have been instrumented into it; it is only useful together with /infer and is described in Inference. /printInlined (boolean, off) prints each implementation after calls to {:inline} procedures have been expanded; see Inlining and loops.

15.5.5 /printCFG🔗

Option

  

Argument

  

Default

/printCFG:prefix

  

path prefix

  

off

After resolution and type checking, writes one Graphviz file per implementation, named prefix.implName.dot. The graph is the loop-processed control flow graph, so it reflects Boogie’s view of the blocks rather than the source’s structured statements.

boogie /printCFG:cfg /noVerify cli-small.bpl > /dev/null ; cat cfg.Abs.dot

digraph G {

  "anon0" [shape=box];

  "anon3_Then" [shape=box];

  "anon3_Else" [shape=box];

  "anon0" -> "anon3_Then";

  "anon0" -> "anon3_Else";

}

15.5.6 /printLean🔗

Option

  

Argument

  

Default

/printLean:file

  

file name

  

off

Completely undocumented. Passifies every implementation and emits the resulting verification conditions as a Lean 4 file that uses the Auto tactic library. The generated file starts with a preamble of SMT array definitions and lemmas and then one theorem per implementation. Verification still runs afterwards unless /noVerify is given. /prune is honoured: with pruning off the whole program’s declarations are emitted.

boogie /printLean:small.lean cli-small.bpl ; head -5 small.lean

 

Boogie program verifier finished with 1 verified, 0 errors

import Auto

import Auto.Tactic

import Auto.MathlibEmulator.Basic -- For `Real`

import Auto.Translation.SMTAttributes

open Lean Std Auto Auto.SMT.Attribute Classical

For the one-procedure program above the generated file is 146 lines: the first 97 are a fixed preamble of SMT array definitions and lemmas, then Variables, Functions, Axioms and Implementations sections, with theorem _boogie_Abs_correct at line 135.

15.5.7 /xml🔗

Option

  

Argument

  

Default

/xml:file

  

file name

  

off

Writes a machine-readable transcript in parallel with the console output: one <method> element per implementation, an <assertionBatch> per VC split with the source location of each assertion, and an <error> element with the execution trace for each failure. Timings and Z3 resource counts are included.

boogie /xml:out.xml cli-abs.bpl > /dev/null ; cat out.xml

<?xml version="1.0" encoding="utf-8"?>

<boogie version="3.5.7.0" commandLine="... /xml:out.xml cli-abs.bpl">

  <file name="cli-abs.bpl">

    <fileFragment name="cli-abs.bpl" />

  </file>

  <error message="postcondition violation" file="cli-abs.bpl" line="11" column="1">

    <related file="cli-abs.bpl" line="8" column="3" />

    <trace>

      <traceNode label="PreconditionGeneratedEntry" />

      <traceNode file="cli-abs.bpl" line="10" column="5" label="anon0" />

    </trace>

  </error>

  <method name="Abs" startTime="2026-08-07 23:09:29Z">

    <assertionBatch number="0" iteration="0" startTime="2026-08-07 23:09:29Z">

      <assertion file="cli-abs.bpl" line="2" column="3" />

      <conclusion duration="0.0264656" outcome="valid" resourceCount="700" />

    </assertionBatch>

    <conclusion endTime="2026-08-07 23:09:29Z" duration="0.0264656" resourceCount="700" outcome="correct" />

  </method>

  <method name="Bad" startTime="2026-08-07 23:09:29Z">

    <assertionBatch number="0" iteration="0" startTime="2026-08-07 23:09:29Z">

      <assertion file="cli-abs.bpl" line="8" column="3" />

      <conclusion duration="0.0144576" outcome="invalid" resourceCount="302" />

    </assertionBatch>

    <conclusion endTime="2026-08-07 23:09:29Z" duration="0.0144576" resourceCount="302" outcome="errors" />

  </method>

</boogie>

(The commandLine attribute has been abbreviated above; it contains the full argument vector including the driver DLL path.)

15.5.8 File-name macros and /logPrefix🔗

Four options expand macros in their file-name argument, in CommandLineOptions.ApplyDefaultOptions that is, after all arguments have been parsed, so the order on the command line does not matter:

Macro

  

Expands to

@TIME@

  

the process start time, ISO 8601 with : replaced by .

@PREFIX@

  

the concatenation of all /logPrefix arguments

@FILE@

  

the last file named on the command line, escaped for use in a file name

@PROC@

  

/proverLog only: one log per verification condition, named after the procedure

The macros are applied to /xml, /print, /proverLog and /printModelToFile. /logPrefix:str appends str to the @PREFIX@ expansion, replacing / and \ with - so the result is always a single path component; it may be given more than once and the values are concatenated.

boogie /logPrefix:XY '/proverLog:log-@PREFIX@-@FILE@.smt2' cli-small.bpl > /dev/null ; ls log-*

log-XY-cli-small.bpl.smt2

15.5.9 /useBaseNameForFileName and /printVerifiedProceduresCount🔗

/useBaseNameForFileName (boolean, off) makes the parser record only the base name of each file in the tokens it produces, so diagnostics are reported against abs.bpl instead of ./some/path/abs.bpl. It also affects the file name printed in "parse errors detected in ..." messages.

/printVerifiedProceduresCount:n (0 or 1, default 1) controls whether the trailer includes the verified count:

boogie /printVerifiedProceduresCount:0 cli-abs.bpl

cli-abs.bpl(11,1): Error: a postcondition could not be proved on this return path

cli-abs.bpl(8,3): Related location: this is the postcondition that could not be proved

Execution trace:

    cli-abs.bpl(10,5): anon0

 

Boogie program verifier finished with 1 error

15.6 Verification-condition generation🔗

15.6.1 Program transformations before VC generation🔗

Option

  

Argument

  

Default

  

Effect

/liveVariableAnalysis:c

  

0, 1 or 2

  

1

  

0 = off, 1 = intraprocedural, 2 = interprocedural. Dead assignments are dropped during passification.

/coalesceBlocks:c

  

0 or 1

  

1

  

Merge a block into its unique predecessor when the predecessor has a unique successor.

/removeEmptyBlocks:c

  

0 or 1

  

1

  

Drop blocks with no commands during VC generation.

/noPruneInfeasibleEdges

  

none

  

pruning on

  

Keep control-flow edges whose guard is syntactically infeasible.

/inferModifies

  

none

  

off

  

Compute modifies clauses instead of requiring them. Forced on for Civl programs.

The effects are visible in the passive program. With the default settings the assignments to a variable that is never read afterwards are gone:

procedure P(b: bool)

{

  var y: int;

  y := 1;

  if (b) {

    y := 2;

  }

  assert true;

}

boogie /liveVariableAnalysis:0 /printPassive:pb.out cli-blocks.bpl > /dev/null ; cat pb.out

 

procedure P(b: bool);

 

 

 

implementation P(b: bool)

{

  var y: int;

  var y#AT#0: int;

 

 

  anon0:

    goto anon3_Then, anon3_Else;

 

  anon3_Else:

    assume {:partition} !b;

    assume y#AT#0 == 1;

    goto anon2;

 

  anon2:

    assert true;

    return;

 

  anon3_Then:

    assume {:partition} b;

    assume y#AT#0 == 2;

    goto anon2;

}

/removeEmptyBlocks:0 keeps the synthetic entry blocks. Running the same command with /removeEmptyBlocks:0 instead of /liveVariableAnalysis:0 yields a body that begins:

PreconditionGeneratedEntry:

  goto 0;

 

0:

  goto anon0;

 

anon0:

  goto anon3_Then, anon3_Else;

/noPruneInfeasibleEdges keeps a branch whose guard is literally false reachable in the graph:

procedure P()

{

  if (false) {

    assert 1 == 2;

  }

  assert true;

}

boogie /noPruneInfeasibleEdges /printPassive:pi.out cli-infeasible.bpl > /dev/null ; cat pi.out

 

procedure P();

 

 

 

implementation P()

{

 

  anon0:

    goto anon3_Then, anon3_Else;

 

  anon3_Else:

    assume {:partition} !false;

    goto anon2;

 

  anon2:

    assert true;

    return;

 

  anon3_Then:

    assume {:partition} false;

    assert 1 == 2;

    goto anon2;

}

By default the edge from anon3_Then to anon2 is removed and anon2 is folded away.

/inferModifies rescues a program that would otherwise fail type checking:

var g: int;

 

procedure P()

{

  g := 1;

}

boogie cli-modifies.bpl

boogie /inferModifies cli-modifies.bpl

cli-modifies.bpl(5,4): Error: command assigns to a global variable that is not in the enclosing procedure's modifies clause: g

1 type checking errors detected in cli-modifies.bpl

 

Boogie program verifier finished with 1 verified, 0 errors

15.6.2 /subsumption🔗

Option

  

Argument

  

Default

/subsumption:c

  

0, 1 or 2

  

2 (always)

After an assertion has been turned into a proof obligation, it is normally also assumed for the rest of the path. 0 never assumes, 1 assumes except for quantified assertions, 2 always assumes. Turning subsumption off makes later assertions independent of earlier ones, at the cost of a harder VC:

procedure P(x: int)

{

  assert x > 0;

  assert x > -1;

}

boogie /subsumption:0 cli-subsumption.bpl

cli-subsumption.bpl(3,3): Error: this assertion could not be proved

Execution trace:

    cli-subsumption.bpl(3,3): anon0

cli-subsumption.bpl(4,3): Error: this assertion could not be proved

Execution trace:

    cli-subsumption.bpl(3,3): anon0

 

Boogie program verifier finished with 0 verified, 2 errors

boogie /subsumption:2 cli-subsumption.bpl

cli-subsumption.bpl(3,3): Error: this assertion could not be proved

Execution trace:

    cli-subsumption.bpl(3,3): anon0

 

Boogie program verifier finished with 0 verified, 1 error

With /subsumption:1 this program behaves like /subsumption:2, since neither assertion is quantified.

The per-assertion attribute {:subsumption n} overrides the command-line setting.

15.6.3 /alwaysAssumeFreeLoopInvariants🔗

Boolean, off by default. A free invariant is always assumed at the loop head, so it is available inside the body and after the loop. What it is normally not part of is the two checking contexts that RemoveBackEdges builds: the block that enters the loop and the back-edge block. With this flag the free invariant is pushed into both (prefixOfPredicateCmdsInit and prefixOfPredicateCmdsMaintained), so two extra assumes appear in the passive program.

procedure P(n: int)

  requires 0 <= n;

{

  var i: int;

  i := 0;

  while (i < n)

    free invariant 0 <= i;

  {

    i := i + 1;

  }

  assert 0 <= i;

}

boogie /printPassive:fi0.out cli-freeinv.bpl > /dev/null

boogie /alwaysAssumeFreeLoopInvariants /printPassive:fi1.out cli-freeinv.bpl > /dev/null

diff fi0.out fi1.out

14c14

<   anon0:

---

>   PreconditionGeneratedEntry:

15a16,19

>     goto anon0;

>

>   anon0:

>     assume 0 <= 0;

24a29

>     assume 0 <= i#AT#1;

assume 0 <= 0 is the invariant at the loop entry (with i still 0) and assume 0 <= i#AT#1 is the invariant at the back edge. Since a free invariant is never proved, adding it to the checking contexts can only weaken the obligations.

15.6.4 /prune🔗

Option

  

Argument

  

Default

/prune:n

  

0 or 1

  

0 (off)

CommandLineOptions.Prune is an auto-property with no initialiser, so its default is false. Pruning is off unless you ask for it.

Pruning removes top-level declarations that the implementation being verified cannot reach, using the dependency graph built from uses clauses, {:include_dep} and quantifier triggers. /printSplitDeclarations makes the difference visible, since it only prints anything when pruning is on:

function F(int): int uses {

  axiom (forall x: int :: F(x) == 2 * x);

}

function G(int): int uses {

  axiom (forall x: int :: G(x) == F(x) + 1);

}

 

procedure P(x: int)

  ensures F(x) - x == x;

{ }

boogie /printSplit:- /printSplitDeclarations cli-prune.bpl

implementation P--1(x: int)

{

 

  PreconditionGeneratedEntry:

    goto anon0;

 

  anon0:

    assert F(x) - x == x;

    return;

}

 

 

 

Boogie program verifier finished with 1 verified, 0 errors

boogie /prune:1 /printSplit:- /printSplitDeclarations cli-prune.bpl

implementation P--1(x: int)

{

 

  PreconditionGeneratedEntry:

    goto anon0;

 

  anon0:

    assert F(x) - x == x;

    return;

}

 

 

function F(int) : int

uses {

axiom (forall x: int :: F(x) == 2 * x);

}

procedure P(x: int);

  ensures F(x) - x == x;

 

 

implementation P(x: int)

{

    assert F(x) - x == x;

}

 

 

 

Boogie program verifier finished with 1 verified, 0 errors

G and its axiom are gone. Two further interactions are worth knowing:

15.6.5 Type and array encoding🔗

Option

  

Argument

  

Default

/typeEncoding:t

  

m/monomorphic, p/predicates, a/arguments

  

m

/useArrayAxioms

  

none

  

off

/reflectAdd

  

none

  

off

/typeEncoding chooses how polymorphism is compiled away. With m, Boogie first tries to monomorphise the whole program; if that fails it prints Unable to monomorphize input program: unhandled polymorphic features detected or ... : expanding type cycle detected and stops — but still exits 0, because the failure is a PipelineOutcome.FatalError raised inside ResolveAndTypecheck, and ProcessProgram treats every non-ResolvedAndTypeChecked outcome as a successful run. Note also that ResolveAndTypecheck overrides the option to Monomorphic whenever MonomorphismChecker.IsMonomorphic succeeds, so on a monomorphic program /typeEncoding:p and /typeEncoding:a have no effect. Datatypes and {:define} functions require monomorphic encoding: under p or a they are rejected with Datatypes only supported with monomorphic encoding / Functions with :define attribute only supported with monomorphic encoding.

UseArrayTheory is derived, not settable: it is !useArrayAxioms && TypeEncodingMethod == Monomorphic. So maps are compiled to the SMT theory of arrays only under monomorphic encoding, and /useArrayAxioms switches to explicit select/store axioms:

procedure P(m: [int]int, i: int, v: int)

{

  assert m[i := v][i] == v;

}

boogie /proverLog:a0.smt2 cli-array.bpl

grep -nE 'Array|select|store' a0.smt2

14:(declare-fun m () (Array Int Int))

25: (=> (= (ControlFlow 0 0) 3) (let ((anon0_correct  (=> (= (ControlFlow 0 2) (- 0 1)) (= (select (store m i v) i) v))))

boogie /useArrayAxioms /proverLog:a1.smt2 cli-array.bpl

grep -nE 'Select__|Store__' a1.smt2

15:(declare-fun |Select__T@[Int]Int_| (|T@[Int]Int| Int) Int)

16:(declare-fun |Store__T@[Int]Int_| (|T@[Int]Int| Int Int) |T@[Int]Int|)

17:(assert (forall ( ( ?x0 |T@[Int]Int|) ( ?x1 Int) ( ?x2 Int)) (! (= (|Select__T@[Int]Int_| (|Store__T@[Int]Int_| ?x0 ?x1 ?x2) ?x1)  ?x2) :weight 0)))

18:(assert (forall ( ( ?x0 |T@[Int]Int|) ( ?x1 Int) ( ?y1 Int) ( ?x2 Int)) (! (=>  (not (= ?x1 ?y1)) (= (|Select__T@[Int]Int_| (|Store__T@[Int]Int_| ?x0 ?x1 ?x2) ?y1) (|Select__T@[Int]Int_| ?x0 ?y1))) :weight 0)))

30: (=> (= (ControlFlow 0 0) 3) (let ((anon0_correct  (=> (= (ControlFlow 0 2) (- 0 1)) (= (|Select__T@[Int]Int_| (|Store__T@[Int]Int_| m i v) i) v))))

/reflectAdd does nothing with the shipped back end. The only reader of ReflectAdd is VCExprASTPrinter.VisitAddOp, which is used for debug printing of VC expressions; the SMT-LIB output is produced by SMTLibLineariser, which never consults it. Comparing prover logs with and without the flag shows identical (+ a b) terms.

15.6.6 Prover-input stability🔗

Option

  

Argument

  

Default

/emitDebugInformation:n

  

0 or 1

  

1

/normalizeNames:n

  

0 or 1

  

0

/normalizeDeclarationOrder:n

  

0 or 1

  

1

/randomSeed:s

  

integer

  

unset

/randomizeVcIterations:n

  

integer >= 1

  

1

/randomSeedIterations:n

  

deprecated synonym

  

/emitDebugInformation:0 suppresses the :qid and :skolemid annotations on quantifiers and the (set-info :boogie-vc-id ...) line. /normalizeNames:1 replaces Boogie names in the SMT input with $generated, $generated@@0, ... so that renaming a declaration in the source does not change the solver’s input:

boogie /proverLog:n0.smt2 cli-small.bpl

boogie /normalizeNames:1 /proverLog:n1.smt2 cli-small.bpl

sed -n '13,16p' n0.smt2 ; echo ---- ; sed -n '13,16p' n1.smt2

(declare-fun ControlFlow (Int Int) Int)

(declare-fun r@1 () Int)

(declare-fun x () Int)

(declare-fun r@0 () Int)

----

(declare-fun ControlFlow (Int Int) Int)

(declare-fun $generated () Int)

(declare-fun $generated@@0 () Int)

(declare-fun $generated@@1 () Int)

/randomizeVcIterations:n proves each VC n times with different random seeds, renaming variables and reordering declarations each time and setting matching solver options. It sets RandomSeed to 0 if /randomSeed was not given. /randomSeedIterations is a deprecated spelling of the same option, still accepted and undocumented. The per-implementation attributes {:random_seed N} override /randomSeed for one implementation.

boogie /randomizeVcIterations:3 /trace cli-small.bpl

Parsing cli-small.bpl

Coalescing blocks...

Inlining...

 

Verifying Abs ...

[TRACE] Using prover: z3

  [0.042 s, solver resource count: 2070, 3 proof obligations]  verified

 

Boogie program verifier finished with 1 verified, 0 errors

The single assertion has become three proof obligations.

15.6.7 /keepQuantifier and pool instantiation🔗

Boolean, off by default. Pool-based quantifier instantiation (the {:pool} / {:add_to_pool} attributes) normally replaces a quantifier by the conjunction or disjunction of its instances. /keepQuantifier keeps the original quantifier alongside the instances. With the flag, the quantifier survives into the SMT input:

function F(int): int;

 

procedure P()

{

  assume (forall {:pool "A"} x: int :: F(x) == x);

  assert {:add_to_pool "A", 3} F(3) == 3;

}

boogie /proverLog:q0.smt2 cli-pool.bpl

boogie /keepQuantifier /proverLog:q1.smt2 cli-pool.bpl

grep -c forall q0.smt2 q1.smt2

q0.smt2:0

q1.smt2:1

15.7 Error reporting🔗

15.7.1 /errorLimit🔗

Option

  

Argument

  

Default

/errorLimit:n

  

non-negative integer

  

5

The maximum number of counterexamples extracted per verification condition. 0 means "keep going until every assertion has been falsified or proved". Note that this counts errors per VC, so splitting changes what it means.

procedure Many(a: int, b: int, c: int, d: int)

{

  assert a == 1;

  assert b == 2;

  assert c == 3;

  assert d == 4;

}

boogie cli-errs.bpl

cli-errs.bpl(3,3): Error: this assertion could not be proved

Execution trace:

    cli-errs.bpl(3,3): anon0

cli-errs.bpl(4,3): Error: this assertion could not be proved

Execution trace:

    cli-errs.bpl(3,3): anon0

cli-errs.bpl(5,3): Error: this assertion could not be proved

Execution trace:

    cli-errs.bpl(3,3): anon0

cli-errs.bpl(6,3): Error: this assertion could not be proved

Execution trace:

    cli-errs.bpl(3,3): anon0

 

Boogie program verifier finished with 0 verified, 4 errors

boogie /errorLimit:2 cli-errs.bpl

cli-errs.bpl(3,3): Error: this assertion could not be proved

Execution trace:

    cli-errs.bpl(3,3): anon0

cli-errs.bpl(4,3): Error: this assertion could not be proved

Execution trace:

    cli-errs.bpl(3,3): anon0

 

Boogie program verifier finished with 0 verified, 2 errors

ApplyDefaultOptions silently forces ErrorLimit = 1 when stratified inlining is active and the SMTLib back end is in use. Stratified inlining cannot be turned on from Boogie’s command line, so this only affects tools like Corral that subclass these options.

15.7.2 /errorTrace🔗

Option

  

Argument

  

Default

/errorTrace:n

  

0, 1 or 2

  

1

0 prints only the error line. 1 prints the labelled execution trace. 2 is documented as "include all Trace labels"; in practice the difference from 1 is rarely visible.

boogie /errorTrace:0 cli-trace.bpl

boogie /errorTrace:1 cli-trace.bpl

cli-trace.bpl(8,3): Error: this assertion could not be proved

 

Boogie program verifier finished with 0 verified, 1 error

 

cli-trace.bpl(8,3): Error: this assertion could not be proved

Execution trace:

    cli-trace.bpl(3,3): anon0

    cli-trace.bpl(4,7): anon4_Then

    cli-trace.bpl(8,3): anon3

 

Boogie program verifier finished with 0 verified, 1 error

/errorTrace:0 also suppresses the counterexample model. The code that honours /printModel and /enhancedErrorMessages sits inside the if (Options.ErrorTrace > 0) branch, so /errorTrace:0 /printModel:1 prints neither trace nor model.

15.7.3 /printModel, /printModelToFile and /mv🔗

Option

  

Argument

  

Default

/printModel:n

  

exactly 0 or 1

  

0

/printModelToFile:file

  

file name

  

off

/mv:file

  

file name

  

off

/printModel:1 prints the solver’s counterexample model after each error’s execution trace. Unlike most integer options, this one is parsed by comparing the argument string against "0" and "1", so /printModel:2 is rejected.

boogie /printModel:1 cli-trace.bpl

cli-trace.bpl(8,3): Error: this assertion could not be proved

Execution trace:

    cli-trace.bpl(3,3): anon0

    cli-trace.bpl(4,7): anon4_Then

    cli-trace.bpl(8,3): anon3

*** MODEL

r ->

r@0 -> 1

r@1 -> 1

x -> (- 1)

ControlFlow -> {

  0 0 -> 5

  0 2 -> (- 1)

  0 3 -> 2

  0 5 -> 3

  else -> 5

}

tickleBool -> {

  false -> true

  true -> true

  else -> true

}

*** STATE <initial>

  r ->

  x -> (- 1)

*** END_STATE

*** END_MODEL

 

Boogie program verifier finished with 0 verified, 1 error

/printModelToFile:f sends the model to f instead of the console — the call site is error.Model.Write(Options.ModelWriter ?? errorInfo.Out) so /printModel:1 /printModelToFile:f prints no model at all on standard output.

/mv:file writes the model annotated with {:captureState} points. Each assume {:captureState "s"} ... in the program becomes a *** STATE s section listing the variables whose incarnation changed:

procedure P(x: int) returns (r: int)

{

  assume {:captureState "start"} true;

  r := x;

  assume {:captureState "afterAssign"} true;

  assert r == x + 1;

}

boogie /mv:mv.out cli-capture.bpl > /dev/null ; cat mv.out

*** MODEL

r ->

x -> 0

ControlFlow -> {

  0 0 -> 3

  0 2 -> (- 1)

  0 3 -> 2

  else -> (- 1)

}

tickleBool -> {

  false -> true

  true -> true

  else -> true

}

*** STATE <initial>

  r ->

  x -> 0

*** END_STATE

*** STATE start

*** END_STATE

*** STATE afterAssign

  r -> 0

*** END_STATE

*** END_MODEL

/mv does not need /printModel; setting ModelViewFile is enough to make ExpectingModel true, which is what causes the solver to be asked for a model at all.

15.7.4 /enhancedErrorMessages🔗

Option

  

Argument

  

Default

/enhancedErrorMessages:n

  

0 or 1

  

0

With 1, statements carrying {:print e0, e1, ...} contribute an "augmented execution trace" showing the values of those expressions in the counterexample.

procedure P(x: int, y: int)

{

  assert {:print x, y, x + y} x == y;

}

boogie /enhancedErrorMessages:1 cli-print.bpl

cli-print.bpl(3,3): Error: this assertion could not be proved

Execution trace:

    cli-print.bpl(3,3): anon0

Augmented execution trace:

45x + y

 

Boogie program verifier finished with 0 verified, 1 error

That output is not a typo. ConditionGeneration.AddDebugInfo substitutes model values only for arguments that are plain IdentifierExprs; any other expression is printed as-is. And ExecutionEngine writes the elements with Write, with no separator. So x -> 4, y -> 5 and the literal text x + y are concatenated into 45x + y, followed by the newline the attribute handler appends.

15.7.5 /forceBplErrors🔗

Boolean, off. An assertion carrying {:msg "..."} normally reports that message instead of Boogie’s own. /forceBplErrors restores the standard message:

procedure P(x: int)

{

  assert {:msg "custom message"} x == 1;

}

boogie cli-msg.bpl

boogie /forceBplErrors cli-msg.bpl

custom message

Execution trace:

    cli-msg.bpl(3,3): anon0

 

Boogie program verifier finished with 0 verified, 1 error

 

cli-msg.bpl(3,3): Error: this assertion could not be proved

Execution trace:

    cli-msg.bpl(3,3): anon0

 

Boogie program verifier finished with 0 verified, 1 error

15.7.6 /trackVerificationCoverage and /warnVacuousProofs🔗

Option

  

Argument

  

Default

/trackVerificationCoverage

  

none

  

off

/warnVacuousProofs

  

none

  

off

/trackVerificationCoverage asks the solver for an unsat core and reports which program elements labelled with {:id "..."} were needed for the proof. It replaces the old undocumented /printNecessaryAssertions.

It requires /trace to print anything. Both report sites are guarded by Options.Trace:

procedure P(x: int)

  requires {:id "reqPos"} 0 < x;

  requires {:id "reqBig"} 100 < x;

{

  assert {:id "goal"} 0 <= x;

}

boogie /trackVerificationCoverage cli-coverage.bpl

 

Boogie program verifier finished with 1 verified, 0 errors

boogie /trackVerificationCoverage /trace cli-coverage.bpl

Parsing cli-coverage.bpl

Coalescing blocks...

Inlining...

 

Verifying P ...

[TRACE] Using prover: z3

Proof dependencies:

  goal

  reqPos

  [0.029 s, solver resource count: 547, 1 proof obligation]  verified

Proof dependencies of whole program:

  goal

  reqPos

 

Boogie program verifier finished with 1 verified, 0 errors

reqBig is absent, so it was not needed.

/warnVacuousProofs is a superset: it adds synthetic {:id} attributes to every assumption, assertion, requires, ensures and call, turns on TrackVerificationCoverage (the getter returns trackVerificationCoverage || WarnVacuousProofs), and warns when a proof goal was discharged without being covered. It reports without /trace:

procedure P(x: int)

{

  assume x == 1;

  assume x == 2;

  assert x == 3;

}

boogie /warnVacuousProofs cli-vacuous.bpl

cli-vacuous.bpl(5,2): Warning: Proved vacuously

 

Boogie program verifier finished with 1 verified, 0 errors

Both options make ProduceUnsatCores true, which changes the SMT-LIB stream ((set-option :produce-unsat-cores true) and named assertions) and can therefore change solver performance.

15.7.7 /smoke and /smokeTimeout🔗

Option

  

Argument

  

Default

/smoke

  

none

  

off

/smokeTimeout:n

  

seconds

  

10

The soundness smoke test inserts assert false at various points and reports the ones the prover can discharge — those points are unreachable, which usually means an over-constrained assume or requires has silently made part of the program vacuous.

procedure P(x: int)

  requires 0 < x;

{

  var y: int;

  if (x < 0) {

    y := 1;

  } else {

    y := 2;

  }

}

boogie /smoke cli-smoke.bpl

found unreachable code:

implementation P(x: int)

{

  var y: int;

 

  0:

    goto anon0;

 

  anon0:

    goto anon3_Then;

 

  anon3_Then:

    assume {:partition} x < 0;

    y := 1;

    assert false;

    return;

}

 

 

 

Boogie program verifier finished with 1 verified, 0 errors

Remember that /smoke sets Prune = false while the option is parsed.

15.8 Resource limits🔗

Option

  

Argument

  

Default

  

Applies to

/timeLimit:n

  

seconds (uint)

  

0 = unlimited

  

one verification condition

/rlimit:n

  

Z3 resource units (uint)

  

0 = unlimited

  

one verification condition

/processTimeLimit:n

  

seconds (uint)

  

0 = unlimited

  

the whole boogie invocation

/timeLimitPerAssertionInPercent:n

  

percent, > 0

  

10

  

timeout diagnostics only

/vcsKeepGoingTimeout:n

  

seconds (uint)

  

1

  

keep-going splits

/vcsFinalAssertTimeout:n

  

seconds (uint)

  

30

  

the last single assertion in keep-going mode

/smokeTimeout:n

  

seconds (uint)

  

10

  

smoke-test queries

/timeLimit is turned into (set-option :timeout n000) per query; /rlimit into (set-option :rlimit n). The per-implementation attributes {:timeLimit N} and {:rlimit N} override them.

/processTimeLimit is described in the source as "a hidden option" and is not in the help. It cancels the top-level task after the given number of seconds. The cancellation propagates as PipelineOutcome.Cancelled, which falls through ProcessProgram’s switch to the default arm, so the run produces no output at all and exits 1:

time ( boogie /processTimeLimit:2 cli-timeout1.bpl ; echo "exit=$?" )

exit=1

 

real 0m2.203s

user 0m0.305s

sys 0m0.042s

(Without the limit that program runs for minutes.)

15.8.1 How a timeout is reported🔗

This is the most surprising corner of the option set. Whether a timeout looks like a timeout depends on how many assertions are in the split.

If the split contains more than one assertion, the outcome is a proper time-out:

function {:bvbuiltin "bvmul"} bvmul(bv64, bv64): bv64;

function {:bvbuiltin "bvult"} bvult(bv64, bv64): bool;

 

procedure Factor(x: bv64, y: bv64, k: int)

  requires bvult(1bv64, x) && bvult(1bv64, y);

  requires bvult(x, 4294967296bv64) && bvult(y, 4294967296bv64);

{

  assert k == k;

  assert bvmul(x, y) != 9223372036854775783bv64;

}

boogie /timeLimit:5 cli-timeout.bpl

cli-timeout.bpl(4,11): Verification of 'Factor' timed out after 5 seconds

 

Boogie program verifier finished with 0 verified, 0 errors, 1 time out

Remove the trivial first assertion and the split becomes what Split.LastChance calls a last chance — one assertion, nothing left to split. HandleProverFailure then manufactures a counterexample for it and sets the outcome to Errors:

boogie /timeLimit:5 cli-timeout1.bpl

cli-timeout1.bpl(8,3): Error: this assertion could not be proved

Execution trace:

    cli-timeout1.bpl(8,3): anon0

 

Boogie program verifier finished with 0 verified, 1 error

A single-assertion timeout is indistinguishable from a genuine assertion failure. The same asymmetry applies to /rlimit:

boogie /rlimit:100000 cli-timeout.bpl

boogie /rlimit:100000 cli-timeout1.bpl

cli-timeout.bpl(4,11): Verification out of resource (Factor)

 

Boogie program verifier finished with 0 verified, 0 errors, 1 out of resource

cli-timeout1.bpl(8,3): Error: this assertion could not be proved

Execution trace:

    cli-timeout1.bpl(8,3): anon0

 

Boogie program verifier finished with 0 verified, 1 error

15.8.2 /runDiagnosticsOnTimeout and /traceDiagnosticsOnTimeout🔗

Both are undocumented booleans, off by default. When a query times out, /runDiagnosticsOnTimeout bisects the assertions of the split, re-checking subsets with a smaller per-assertion time limit (TimeLimit / 100 * TimeLimitPerAssertionInPercent milliseconds, or 1000 ms if /timeLimit was not given), until it can name the assertions that individually time out:

boogie /runDiagnosticsOnTimeout /timeLimit:5 cli-timeout.bpl

cli-timeout.bpl(4,11): Verification of 'Factor' timed out after 5 seconds with 1 check(s) that timed out individually

cli-timeout.bpl(9,3): Unverified check due to timeout: this assertion could not be proved

 

Boogie program verifier finished with 0 verified, 0 errors, 1 time out

/traceDiagnosticsOnTimeout adds a report of the search itself:

boogie /runDiagnosticsOnTimeout /traceDiagnosticsOnTimeout /timeLimit:5 cli-timeout.bpl

Starting timeout diagnostics with initial time limit 5000.

Terminated timeout diagnostics after 1013 ms and 3 prover queries.

Outcome: TimeOut

Unverified assertions: 1 (of 2)

cli-timeout.bpl(4,11): Verification of 'Factor' timed out after 5 seconds with 1 check(s) that timed out individually

cli-timeout.bpl(9,3): Unverified check due to timeout: this assertion could not be proved

 

Boogie program verifier finished with 0 verified, 0 errors, 1 time out

The per-assertion limit here is 5000 / 100 * 10 = 500 ms, from /timeLimitPerAssertionInPercent’s default of 10.

/runDiagnosticsOnTimeout also changes cache behaviour: a cached TimedOut result is re-verified rather than reused.

15.9 Prover selection and options🔗

15.9.1 /proverDll🔗

Option

  

Argument

  

Default

/proverDll:tp

  

back-end name or DLL path

  

SMTLib

A name without a path separator is resolved to Boogie.Provers.tp.dll next to the executing assembly; a name containing / or \ is used as a path. The DLL must export Microsoft.Boogie.tp.Factory.

In practice SMTLib is the only usable value. Boogie.Provers.LeanAuto.dll also ships, but it does not export a Factory type. Lean output is available through /printLean instead.

The option is processed eagerly, during parsing, which is why it must precede /proverHelp.

15.9.2 /proverOpt (/p)🔗

Option

  

Argument

  

Default

/proverOpt:KEY[=VALUE]

  

repeatable

  

none

/p:KEY[=VALUE]

  

short form

  

none

Options accumulate and are handed to the back end after parsing. An unrecognised key becomes a ProverException at verification time — and therefore exit code 1:

boogie /proverOpt:NOPE=1 cli-small.bpl ; echo "exit=$?"

Fatal Error: ProverException: Unrecognised prover option: NOPE=1

exit=1

Either = or : separates key from value, and a bare key sets the value to the empty string. The keys the shipped back end accepts (/proverHelp):

Key

  

Type

  

Meaning

PROVER_PATH

  

string

  

full path to the solver binary

PROVER_NAME

  

string

  

solver executable name, looked up on PATH

LOG_FILE

  

string

  

like /proverLog; @PROC@ supported

APPEND_LOG_FILE

  

bool

  

append rather than overwrite

FORCE_LOG_STATUS

  

bool

  

has no effect see below

MEMORY_LIMIT

  

int

  

solver memory limit in megabytes

VERBOSITY

  

int

  

1 echoes the solver’s replies and the launch line; 2 additionally echoes every command sent

TIME_LIMIT

  

uint

  

per-VC time limit in milliseconds

BATCH_MODE

  

bool

  

send all solver input in one batch instead of incrementally

SOLVER

  

string

  

z3 (default), cvc5, yices2, noop

LOGIC

  

string

  

emit (set-logic ...); defaults to empty for Z3 and to ALL for CVC5 and Yices2

USE_WEIGHTS

  

bool

  

emit :weight annotations (default true)

INSPECTOR

  

string

  

path to a Z3Inspector binary

O:<name>=<value>

  

  

emit (set-option :name value)

C:<string>

  

  

pass a literal argument on the solver's command line

FORCE_LOG_STATUS is accepted by the parser but is neither listed in /proverHelp nor read anywhere: ForceLogStatus has no reader, and setting it leaves the prover log byte-for-byte unchanged.

SOLVER=noop runs no solver at all and returns unknown for every query, which is useful for measuring Boogie’s own cost:

boogie /proverOpt:SOLVER=noop cli-abs.bpl

cli-abs.bpl(1,11): Verification inconclusive (Abs)

cli-abs.bpl(7,11): Verification inconclusive (Bad)

 

Boogie program verifier finished with 0 verified, 0 errors, 2 inconclusives

If the solver binary cannot be found the run fails hard:

boogie /proverOpt:PROVER_PATH=/nonexistent/z3 cli-small.bpl ; echo "exit=$?"

Fatal Error: ProverException: Cannot find specified prover: /nonexistent/z3

exit=1

15.9.3 /proverLog, /proverLogAppend and /proverPreamble🔗

Option

  

Argument

  

Default

/proverLog:file

  

file name with macros

  

off

/proverLogAppend

  

none

  

overwrite

/proverPreamble:file

  

file name

  

off

/proverLog records the exact SMT-LIB 2 stream sent to the solver. In addition to the macros of File-name macros and /logPrefix, @PROC@ splits the log into one file per verification condition:

boogie '/proverLog:p-@PROC@.smt2' cli-abs.bpl > /dev/null ; ls p-*.smt2

p-Abs.smt2

p-Bad.smt2

A log begins with the solver options Boogie sets and then the VC:

head -20 p-Abs.smt2

(set-option :print-success false)

(set-info :smt-lib-version 2.6)

(set-option :smt.mbqi false)

(set-option :model.compact false)

(set-option :model.v2 true)

(set-option :pp.bv_literals false)

; done setting options

 

 

(declare-fun tickleBool (Bool) Bool)

(assert (and (tickleBool true) (tickleBool false)))

(push 1)

(declare-fun ControlFlow (Int Int) Int)

(declare-fun r@1 () Int)

(declare-fun x () Int)

(declare-fun r@0 () Int)

(set-info :boogie-vc-id Abs)

(set-option :timeout 0)

(set-option :rlimit 0)

(set-option :smt.mbqi false)

/proverPreamble:file is undocumented. It does not inline the file’s text; it emits a single (include "file") command into the stream, right after the standard preamble. The path is interpreted by the solver, not by Boogie:

boogie /proverPreamble:pre.txt /proverLog:pre.smt2 cli-small.bpl > /dev/null

sed -n '10,13p' pre.smt2

(declare-fun tickleBool (Bool) Bool)

(assert (and (tickleBool true) (tickleBool false)))

(include "pre.txt")

(push 1)

15.9.4 Other prover-facing options🔗

Option

  

Argument

  

Default

  

Effect

/proverWarnings:n

  

0, 1 or 2

  

0

  

Where to print warnings reported by the solver: nowhere, stdout, stderr.

/restartProver

  

none

  

off

  

Kill and restart the solver process after each verification condition — the field is RestartProverPerVC and it is set at the end of CheckOutcomeCore, once per checked VC. Slow, but it removes cross-VC solver state as a variable when chasing instability.

/enableUnSatCoreExtraction:n

  

integer

  

0

  

Undocumented. Its only effect is to make ProduceUnsatCores true when it equals 1, which turns on named assertions and (set-option :produce-unsat-cores true). Unlike other integer options it is parsed with a bare Int32.Parse.

/useProverEvaluate

  

none

  

off

  

Undocumented. Use the prover’s (get-value ...) instead of the model to read variable values. In Boogie it only has the side effect of forcing ProduceModel on (and, under stratified inlining, suppressing model generation); the evaluation path itself is used by Corral.

/boolControlVC

  

none

  

off

  

Undocumented. Emit control-flow as boolean control variables rather than the ControlFlow function. Only meaningful under stratified inlining, which Boogie’s own command line cannot enable.

/vcBrackets:b

  

0 or 1

  

-1 (unset)

  

Has no effect. BracketIdsInVC is initialised to -1 and has no reader anywhere in the source apart from its own property.

15.10 Splitting and parallelism🔗

Boogie can break one implementation’s verification condition into several independent VCs. Splitting is driven by a cost model; the options below tune it. Per-implementation attributes {:vcs_max_cost}, {:vcs_max_splits}, {:vcs_max_keep_going_splits} and {:vcs_split_on_every_assert} override the corresponding options.

Option

  

Argument

  

Default

/vcsMaxCost:f

  

double

  

1.0

/vcsMaxSplits:n

  

integer

  

1

/vcsMaxKeepGoingSplits:n

  

integer

  

1

/vcsKeepGoingTimeout:n

  

uint seconds

  

1

/vcsFinalAssertTimeout:n

  

uint seconds

  

30

/vcsPathJoinMult:f

  

double

  

0.8

/vcsPathCostMult:f

  

double

  

1.0

/vcsAssumeMult:f

  

double

  

0.01

/vcsPathSplitMult:f

  

double

  

0.5

/vcsSplitOnEveryAssert

  

none

  

off

/vcsDumpSplits

  

none

  

off

/vcsCores:n

  

integer >= 1

  

1

/vcsLoad:f

  

double 0.0 <= f < 3.0

  

15.10.1 /vcsMaxCost🔗

VcsMaxCost is initialised to 1.0. With that default, raising /vcsMaxSplits splits immediately, because almost every VC costs more than 1.0.

procedure Four(x: int)

{

  assert x == x;

  assert x + 0 == x;

  assert x * 1 == x;

  assert x - x == 0;

}

boogie /vcsMaxSplits:4 /trace cli-four.bpl

Verifying Four ...

[TRACE] Using prover: z3

    checking split 1/4, 0.00%, (cost:4/1 last) ...

      --> split #1 done,  [0.0410743 s] Valid

    checking split 2/4, 25.00%, (cost:4/1 last) ...

      --> split #2 done,  [0.009278 s] Valid

    checking split 3/4, 50.00%, (cost:4/1 last) ...

      --> split #3 done,  [0.0022301 s] Valid

    checking split 4/4, 75.00%, (cost:4/1 last) ...

      --> split #4 done,  [0.0020062 s] Valid

  [0.055 s, solver resource count: 440, 4 proof obligations]  verified

boogie /vcsMaxSplits:4 /vcsMaxCost:2000.0 /trace cli-four.bpl

Verifying Four ...

[TRACE] Using prover: z3

  [0.038 s, solver resource count: 158, 4 proof obligations]  verified

With a large enough /vcsMaxCost the same command does not split at all. Note also that after the first round of splitting SplitAndVerifyWorker resets maxVcCost to 1.0 regardless, so the option only ever controls the first round.

15.10.2 The splitting cost model🔗

The cost of a block is

(<assert-cost> + vcsAssumeMult * <assume-cost>) * (1.0 + vcsPathCostMult * <entering-paths>)

where each individual assertion and assumption costs 1.0. vcsPathJoinMult scales the path count where control flow joins. When a VC exceeds vcsMaxCost, the splitter compares the best path split (into VCs of cost B and C, from an original of cost A) against vcsPathSplitMult: path splitting is used when A >= vcsPathSplitMult * (B+C), otherwise the assertions are split instead. Raising vcsPathSplitMult favours assertion splitting.

/vcsMaxKeepGoingSplits:n with n > 1 enables keep-going mode: a split that times out is re-split into n pieces and retried. In that mode /vcsKeepGoingTimeout applies to intermediate splits and /vcsFinalAssertTimeout to the final single-assertion split.

15.10.3 /vcsSplitOnEveryAssert and /vcsDumpSplits🔗

/vcsSplitOnEveryAssert puts each assertion in its own VC, ignoring the cost model. It reports which source line each split covers:

boogie /vcsSplitOnEveryAssert /trace cli-errs.bpl

  checking split 1/4 (line 3), 0.00%, (cost:4/1 last) ...

    --> split #1 done,  [0.0292285 s] Invalid

  checking split 2/4 (line 4), 24.26%, (cost:4/1 last) ...

    --> split #2 done,  [0.0073756 s] Invalid

  checking split 3/4 (line 5), 49.01%, (cost:4/1 last) ...

    --> split #3 done,  [0.0019102 s] Invalid

  checking split 4/4 (line 6), 74.26%, (cost:4/1 last) ...

    --> split #4 done,  [0.0019043 s] Invalid

[0.040 s, solver resource count: 1188, 4 proof obligations]  errors

/vcsDumpSplits writes each split to disk as a Graphviz graph and a Boogie implementation, named Impl.split.n.dot and Impl.split.n.bpl:

boogie /vcsDumpSplits /vcsMaxSplits:2 cli-errs.bpl > /dev/null ; ls *.split.*

Many.split.0.bpl

Many.split.0.dot

Many.split.1.bpl

Many.split.1.dot

The .dot labels carry the cost model’s numbers:

cat Many.split.0.dot

digraph G {

n0 -> n1;

n0 [label="PreconditionGeneratedEntry:\n(0.0+0.0)*1.0"];

n1 [label="anon0:\n(2.0+2.0)*1.0",shape=box];

}

The dump happens as part of reading each split’s result, so it takes part in error reporting.

15.10.4 /vcsCores and /vcsLoad🔗

/vcsCores:n verifies up to n VCs concurrently, each with its own checker (and therefore its own solver process). /vcsLoad:f sets it to round(ProcessorCount * f), clamped below at 1; f must be less than 3.0:

boogie /vcsLoad:5 cli-small.bpl

Boogie: Error: surprisingly high load specified; got 5, expected nothing above 3.0

Use /help for available options

The bound is strict: /vcsLoad:3.0 is rejected with the same message, /vcsLoad:2.9 is accepted.

Because output from concurrent workers is serialised per implementation, raising /vcsCores reorders console output relative to a serial run.

15.10.5 /relaxFocus🔗

Boolean, off by default. Controls how {:focus} annotations are turned into splits. The default (top-down) strategy can produce exponentially many splits; /relaxFocus processes foci bottom-up and produces a linear number. On Boogie’s own Test/implementationDivision/focus/focus.bpl:

boogie /printSplit:- /errorTrace:0 focus.bpl | grep '^implementation'

implementation Ex-0() returns (y: int)

implementation Ex-1/focus[+16,-20,-25]/afterSplit@15() returns (y: int)

implementation Ex-2/focus[+16,-20,+25]() returns (y: int)

implementation Ex-3/focus[+16,+20,-25]() returns (y: int)

implementation Ex-4/focus[+16,+20,+25]() returns (y: int)

implementation focusInconsistency--1/focus[+38](x: int) returns (y: int)

boogie /relaxFocus /printSplit:- /errorTrace:0 focus.bpl | grep '^implementation'

implementation Ex-0() returns (y: int)

implementation Ex-1/focus[-25,-20,+16]/afterSplit@15() returns (y: int)

implementation Ex-2/focus[-25,+20,-16]() returns (y: int)

implementation Ex-3/focus[+25,-20,-16]() returns (y: int)

implementation focusInconsistency--1/focus[+38](x: int) returns (y: int)

The +/- lists in the split names are the focus block line numbers that are kept and dropped.

15.11 Inference🔗

15.11.1 Abstract interpretation: /infer🔗

Option

  

Argument

  

Default

/infer:flags

  

a string of flag characters

  

off

/instrumentInfer:c

  

h or e

  

h

/checkInfer

  

none

  

off

/printInstrumented

  

none

  

off

/infer takes a string in which each character is a flag:

Character

  

Meaning

t

  

trivial bottom/top lattice

j

  

intervals (the "stronger" domain)

s

  

debug statistics

0 to 9

  

number of iterations before widening (default 0)

Exactly one of t and j must appear; supplying both or neither is an error, and so is any other character:

boogie /infer:tj cli-infer.bpl

boogie /infer:x cli-infer.bpl

Boogie: Error: Option /infer requires the selection of exactly one abstract domain

Use /help for available options

Boogie: Error: Invalid argument 'x' to option /infer

Boogie: Error: Option /infer requires the selection of exactly one abstract domain

Use /help for available options

s is accepted but the interval domain does not implement it:

Microsoft.Boogie.AbstractInterpretation.NativeIntervalDomain currently does not support debug statistics

The domain matters. This program needs a loop invariant that the trivial domain cannot express:

procedure Down(n: int) returns (i: int)

  requires 0 <= n;

  ensures 0 <= i;

{

  i := n;

  while (0 < i) {

    i := i - 1;

  }

}

boogie cli-infer.bpl

cli-infer.bpl(6,3): Error: a postcondition could not be proved on this return path

cli-infer.bpl(3,3): Related location: this is the postcondition that could not be proved

Execution trace:

    cli-infer.bpl(5,5): anon0

    cli-infer.bpl(6,3): anon2_LoopDone

 

Boogie program verifier finished with 0 verified, 1 error

boogie /infer:t cli-infer.bpl

cli-infer.bpl(6,3): Error: a postcondition could not be proved on this return path

cli-infer.bpl(3,3): Related location: this is the postcondition that could not be proved

Execution trace:

    cli-infer.bpl(5,5): anon0

    cli-infer.bpl(6,3): anon2_LoopHead

    cli-infer.bpl(6,3): anon2_LoopDone

 

Boogie program verifier finished with 0 verified, 1 error

boogie /infer:j cli-infer.bpl

 

Boogie program verifier finished with 1 verified, 0 errors

The trivial domain does insert a cut point (visible as the extra anon2_LoopHead step in the trace), but the invariant it infers is true.

/printInstrumented shows what was added:

boogie /infer:j /printInstrumented /noVerify cli-infer.bpl

procedure Down(n: int) returns (i: int);

  requires 0 <= n;

  ensures 0 <= i;

 

 

 

implementation Down(n: int) returns (i: int)

{

 

  anon0:

    i := n;

    goto anon2_LoopHead;

 

  anon2_LoopHead:  // cut point

    assume {:inferred} 0 <= i;

    goto anon2_LoopDone, anon2_LoopBody;

 

  anon2_LoopBody:

    assume {:partition} 0 < i;

    i := i - 1;

    goto anon2_LoopHead;

 

  anon2_LoopDone:

    assume {:partition} i <= 0;

    return;

}

 

 

 

Boogie program verifier finished with 0 verified, 0 errors

/checkInfer turns each assume {:inferred} into an assert {:inferred}, so the prover has to confirm the abstract interpreter’s results. The only line that changes is:

anon2_LoopHead:  // cut point

  assert {:inferred} 0 <= i;

/instrumentInfer:e instruments the beginning and end of every block instead of only loop headers. The help describes it as a debugging aid for abstract domains, and the output shows why:

boogie /infer:j /instrumentInfer:e /printInstrumented /noVerify cli-infer.bpl

procedure Down(n: int) returns (i: int);

  requires 0 <= n;

  ensures 0 <= i;

 

 

 

implementation Down(n: int) returns (i: int)

{

 

  anon0:

    assume {:inferred} 0 <= n;

    i := n;

    assume {:inferred} 0 <= n && 0 <= i;

    goto anon2_LoopHead;

 

  anon2_LoopHead:  // cut point

    assume {:inferred} 0 <= n && 0 <= i;

    assume {:inferred} 0 <= n && 0 <= i;

    goto anon2_LoopDone, anon2_LoopBody;

 

  anon2_LoopBody:

    assume {:inferred} 0 <= n && 0 <= i;

    assume {:partition} 0 < i;

    i := i - 1;

    assume {:inferred} 0 <= n && 0 <= i;

    goto anon2_LoopHead;

 

  anon2_LoopDone:

    assume {:inferred} 0 <= n && 0 <= i;

    assume {:partition} i <= 0;

    assume {:inferred} 0 <= n && i == 0;

    return;

}

 

 

 

Boogie program verifier finished with 0 verified, 0 errors

15.11.2 Houdini: /contractInfer🔗

Option

  

Argument

  

Default

  

Documented

/contractInfer

  

none

  

off

  

yes

/printAssignment

  

none

  

off

  

no

/explainHoudini

  

none

  

off

  

no

/reverseHoudiniWorklist

  

none

  

off

  

no

/crossDependencies

  

none

  

off

  

no

/useUnsatCoreForContractInfer

  

none

  

off

  

no

/inlineDepth:n

  

integer

  

-1

  

no

/dbgRefuted

  

none

  

off

  

no

Houdini searches for the largest assignment to global boolean constants marked {:existential true} that makes the program verify. Candidate specifications are written as implications guarded by those constants.

const {:existential true} b1: bool;

const {:existential true} b2: bool;

 

var g: int;

 

procedure P(i: int)

  modifies g;

  ensures b1 ==> g > 0;

  ensures b2 ==> g < 0;

{

  if (i > 0) { g := 5; } else { g := 1; }

}

boogie /contractInfer /printAssignment cli-houdini.bpl

Assignment computed by Houdini:

b1 = True

b2 = False

 

Boogie program verifier finished with 1 verified, 0 errors

Without /contractInfer the {:existential} attribute is ignored entirely. /trace shows the refutation loop and its statistics:

boogie /contractInfer /trace cli-houdini.bpl

Parsing cli-houdini.bpl

Coalescing blocks...

Inlining...

Collecting existential constants...

Building call graph...

Number of implementations = 1

[TRACE] Using prover: z3

Beginning VC generation for Houdini...

Generating VC for P

Verifying P

Houdini assignment axiom: Microsoft.Boogie.VCExprAST.VCExprNAryOp(Microsoft.Boogie.VCExprAST.VCExprNAryOp(true, b1), b2)

Outcome = Invalid

Time taken = 0.0204528

Removing b2

Verifying P

Houdini assignment axiom: Microsoft.Boogie.VCExprAST.VCExprNAryOp(Microsoft.Boogie.VCExprAST.VCExprNAryOp(true, b1), Microsoft.Boogie.VCExprAST.VCExprNAryOp(b2))

Outcome = Valid

Time taken = 0.0013537

Number of true assignments = 1

Number of false assignments = 1

Prover time = 0.02

Unsat core prover time = 0.00

Number of prover queries = 2

Number of unsat core prover queries = 0

Number of unsat core prunings = 0

verified

 

Boogie program verifier finished with 1 verified, 0 errors

The "Houdini assignment axiom" lines print the raw .NET ToString() of a VCExprNAryOp.

The remaining options tune the search:

15.11.3 Staged and concurrent Houdini🔗

Option

  

Argument

  

Default

/stagedHoudini:s

  

COARSE, FINE or BALANCED

  

off

/stagedHoudiniThreads:n

  

integer

  

1

/stagedHoudiniReachabilityAnalysis

  

none

  

off

/stagedHoudiniMergeIgnoredAnnotations

  

none

  

off

/debugStagedHoudini

  

none

  

off

/concurrentHoudini

  

none

  

off

/modifyTopologicalSorting

  

none

  

off

/debugConcurrentHoudini

  

none

  

off

/variableDependenceIgnore:file

  

file name

  

off

All of these are undocumented.

/stagedHoudini:s assigns the candidate annotations to stages using the annotation-dependence analysis of AnnotationDependenceAnalyser and then runs the stages as separate Houdini instances; the argument selects the granularity of that assignment. Anything other than the three names is rejected with Boogie: Error: Invalid argument "BOGUS" to option /stagedHoudini. /stagedHoudiniThreads is the number of parallel instances; /stagedHoudiniReachabilityAnalysis builds the dependence graph with a real reachability check instead of the trivial one; /stagedHoudiniMergeIgnoredAnnotations merges annotations the variable-dependence analysis considers irrelevant; /debugStagedHoudini traces the planner.

/concurrentHoudini runs several Houdini instances in parallel, one per entry of Options.Cho, the per-task configuration list read by Houdini.GetErrorLimit. Boogie has no command-line option that populates Cho; only tools that subclass CommandLineOptions and fill it in programmatically (GPUVerify did) supply one. /debugConcurrentHoudini traces the exchange of refuted annotations between the instances, and /modifyTopologicalSorting switches the block orders used by live variable analysis and passification to the reversed topological sort (dag.TopologicalSort(true)).

/variableDependenceIgnore:file names a file of variable names to exclude from the variable-dependence analysis used by staged Houdini.

15.12 Inlining and loops🔗

15.12.1 /inline and /printInlined🔗

Option

  

Argument

  

Default

/inline:i

  

none, assume, assert or spec

  

assume

/printInlined

  

none

  

off

Inlining happens only if some procedure or implementation carries an {:inline N} attribute; otherwise the pass is skipped entirely. /inline says what to do at a call site once the depth budget N runs out:

Value

  

At exhausted depth

  

Callee verified?

assume

  

replace the call by assume false

  

no

assert

  

replace the call by assert false

  

no

spec

  

leave the call, using the contract

  

yes

none

  

ignore the attribute entirely

  

yes

procedure {:inline 1} Double(x: int) returns (y: int)

{

  y := 2 * x;

}

 

procedure Main()

{

  var a: int;

  call a := Double(3);

  assert a == 6;

}

With the default the call is expanded and Double itself is not verified. With /inline:none the call uses Double’s (empty) contract, so the assertion fails:

boogie cli-inline.bpl

boogie /inline:none cli-inline.bpl

 

Boogie program verifier finished with 1 verified, 0 errors

 

cli-inline.bpl(10,3): Error: this assertion could not be proved

Execution trace:

    cli-inline.bpl(9,3): anon0

 

Boogie program verifier finished with 1 verified, 1 error

Which implementations get verified is easy to see with /trace:

for i in none assume assert spec ; do

  boogie /inline:$i /trace cli-inline.bpl | grep -E 'Verifying|finished'

done

Verifying Double ...

Verifying Main ...

Boogie program verifier finished with 1 verified, 1 error

Verifying Main ...

Boogie program verifier finished with 1 verified, 0 errors

Verifying Main ...

Boogie program verifier finished with 1 verified, 0 errors

Verifying Double ...

Verifying Main ...

Boogie program verifier finished with 2 verified, 0 errors

/printInlined prints each implementation after expansion, to the console:

boogie /printInlined /noVerify cli-inline.bpl

after inlining procedure calls

procedure Main();

 

 

implementation Main()

{

  var a: int;

  var inline$Double$0$x: int;

  var inline$Double$0$y: int;

 

  anon0:

    goto inline$Double$0$Entry;

 

  inline$Double$0$Entry:

    inline$Double$0$x := 3;

    havoc inline$Double$0$y;

    goto inline$Double$0$anon0;

 

  inline$Double$0$anon0:

    inline$Double$0$y := 2 * inline$Double$0$x;

    goto inline$Double$0$Return;

 

  inline$Double$0$Return:

    a := inline$Double$0$y;

    goto anon0$1;

 

  anon0$1:

    assert a == 6;

    return;

}

 

 

 

Boogie program verifier finished with 0 verified, 0 errors

15.12.2 Loop options🔗

Option

  

Argument

  

Default

/loopUnroll:n

  

integer

  

-1 (do not unroll)

/soundLoopUnrolling

  

none

  

off

/kInductionDepth:k

  

integer

  

-1 (off)

/extractLoops

  

none

  

off

/deterministicExtractLoops

  

none

  

off

/loopUnroll:n replaces each loop by n copies of its body and drops the executions that would need more iterations. That is unsound by design: a program that fails with a missing invariant may verify after unrolling.

procedure Sum(n: int) returns (s: int)

  requires 0 <= n;

  ensures 0 <= s;

{

  var i: int;

  i := 0; s := 0;

  while (i < n) {

    s := s + i;

    i := i + 1;

  }

}

boogie cli-loop.bpl

boogie /loopUnroll:3 cli-loop.bpl

cli-loop.bpl(7,3): Error: a postcondition could not be proved on this return path

cli-loop.bpl(3,3): Related location: this is the postcondition that could not be proved

Execution trace:

    cli-loop.bpl(6,5): anon0

    cli-loop.bpl(7,3): anon2_LoopDone

 

Boogie program verifier finished with 0 verified, 1 error

 

Boogie program verifier finished with 1 verified, 0 errors

/soundLoopUnrolling adds an assertion that the loop really does finish within the bound, which restores soundness and, here, reports the truncation:

boogie /loopUnroll:3 /soundLoopUnrolling cli-loop.bpl

cli-loop.bpl(7,3): Error: this assertion could not be proved

Execution trace:

    cli-loop.bpl(6,5): anon0#3

    cli-loop.bpl(8,7): anon2_LoopBody#3

    cli-loop.bpl(8,7): anon2_LoopBody#2

    cli-loop.bpl(8,7): anon2_LoopBody#1

    cli-loop.bpl(7,3): anon2_LoopHead#0

 

Boogie program verifier finished with 0 verified, 1 error

/extractLoops converts irreducible loops to reducible form by node splitting and turns every loop into a recursive procedure, which then shows up as its own verification task:

boogie /extractLoops /trace cli-loop.bpl | grep -E 'Verifying|finished|Error'

Verifying Sum ...

cli-loop.bpl(7,3): Error: a postcondition could not be proved on this return path

Verifying Sum_loop_anon2_LoopHead ...

Boogie program verifier finished with 1 verified, 1 error

/deterministicExtractLoops removes the non-determinism the plain extraction introduces: the loop procedure’s entry block no longer has a nondeterministic branch to an immediate exit block, the blocks that break out of the loop are added to the loop’s footprint (so their assignments become out-parameters), and dead-end blocks are not given an assume false. Note that the name appears both as a case label taking no argument and as a boolean flag in the default branch; the case label wins, but the two do the same thing.

/kInductionDepth:k replaces loop reasoning with combined-case k-induction, unwinding proportionally to k. It is sound but usually needs a carefully chosen k; -1 disables it — but that value cannot be written on the command line, because the option is read with ps.GetIntArgument, whose default filter rejects negative numbers:

boogie /kInductionDepth:-1 cli-small.bpl ; echo "exit=$?"

Boogie: Error: Invalid argument "-1" to option /kInductionDepth

Use /help for available options

exit=1

-1 is only reachable as the field’s initial value, i.e. by not passing the option at all.

15.12.3 Stratified inlining🔗

StratifiedInlining can only be set programmatically: no Boogie option turns it on, so /boolControlVC and the StratifiedInlining branches of ApplyDefaultOptions are reachable only from tools that subclass CommandLineOptions, such as Corral.

15.12.4 Lambda-lifting options🔗

Option

  

Argument

  

Default

/freeVarLambdaLifting

  

none

  

off

/printLambdaLifting

  

none

  

off

Lambda expressions are replaced by generated functions plus defining axioms. By default the generated function’s parameters are the maximal sub-expressions of the body that do not mention the bound variables. /freeVarLambdaLifting instead uses the lambda’s free variables.

function F(int): int;

 

procedure P(a: int)

{

  var m: [int]int;

  m := (lambda i: int :: i + F(a) + 1);

  assert m[0] == F(a) + 1;

}

Both commands below print the program twice; only the second, post-lifting copy is reproduced here.

boogie /print:- /printLambdaLifting /env:0 cli-lambda.bpl

implementation P(a: int)

{

  var m: [int]int;

 

    m := lambda#0(F(a), 1);

    assert m[0] == F(a) + 1;

}

 

 

 

// auto-generated lambda function

function lambda#0(l#0: int, l#1: int) : [int]int

uses {

axiom (forall l#0: int, l#1: int, i: int ::

  { lambda#0(l#0, l#1)[i] }

  lambda#0(l#0, l#1)[i] == i + l#0 + l#1);

}

boogie /print:- /printLambdaLifting /freeVarLambdaLifting /env:0 cli-lambda.bpl

implementation P(a: int)

{

  var m: [int]int;

 

    m := lambda#0(a);

    assert m[0] == F(a) + 1;

}

 

 

 

// auto-generated lambda function

function lambda#0(a: int) : [int]int

uses {

axiom (forall a: int, i: int :: { lambda#0(a)[i] } lambda#0(a)[i] == i + F(a) + 1);

}

15.12.5 /printMeasureDesugaring🔗

measure clauses on procedures become a non-negativity precondition plus a decrease check on each recursive call. /printMeasureDesugaring, combined with /print, shows the result:

procedure Down(n: int)

  requires 0 <= n;

  measure n;

{

  if (n > 0) {

    call Down(n - 1);

  }

}

boogie /print:- /printMeasureDesugaring /env:0 cli-measure.bpl

Again only the second copy is shown. The measure clause has become a requires n >= 0 and an assert before the recursive call; note that the desugaring point also forces unstructured printing:

procedure Down(n: int);

  requires 0 <= n;

  requires n >= 0;

 

 

 

implementation Down(n: int)

{

  /*** structured program:

    if (n > 0)

    {

        call Down(n - 1);

    }

  **** end structured program */

 

  anon0:

    goto anon2_Then, anon2_Else;

 

  anon2_Else:

    assume {:partition} 0 >= n;

    return;

 

  anon2_Then:

    assume {:partition} n > 0;

    assert n - 1 < old(n);

    call Down(n - 1);

    return;

}

15.13 Caching and snapshots🔗

Option

  

Argument

  

Default

/verifySnapshots:n

  

0, 1, 2 or 3

  

-1 (option absent)

/traceCaching:n

  

0, 1, 2 or 3

  

0

15.13.1 /verifySnapshots🔗

The field is initialised to -1, but the argument must be in 0..3, so -1 means "the option was not given". This matters because the snapshot search is guarded by 0 <= VerifySnapshots: /verifySnapshots:0 is not the same as omitting the option.

When the option is present, the file names on the command line are treated as base names. For each f.bpl, Boogie looks for f.v0.bpl, f.v1.bpl, ... and verifies each existing version in turn, as a separate program. The base file itself is never opened:

snap/prog.v0.bpl declares two trivially correct procedures; snap/prog.v1.bpl is the same file with Q’s assertion changed to assert 2 == 3; and its checksum bumped.

ls snap/

prog.v0.bpl

prog.v1.bpl

boogie /verifySnapshots:0 snap/prog.bpl

 

Boogie program verifier finished with 2 verified, 0 errors

snap/prog.v1.bpl(8,3): Error: this assertion could not be proved

Execution trace:

    snap/prog.v1.bpl(8,3): anon0

 

Boogie program verifier finished with 1 verified, 1 error

Without the option the same command fails, because snap/prog.bpl does not exist (the absolute path in the second half of the message has been shortened here):

boogie snap/prog.bpl

Error opening file "snap/prog.bpl": Could not find file '.../snap/prog.bpl'.

The levels are:

Level

  

Meaning

0

  

run every snapshot, no result caching

1

  

basic result caching

2

  

advanced caching: unchanged implementations are skipped, and partially-changed ones get cached facts injected

3

  

as 2, and errors are re-reported at the new source locations (excluding /errorTrace and {:captureState} locations)

Caching keys off two attributes: {:checksum "..."} on procedures and implementations, and {:id "..."} on implementations. An implementation is skipped only when its own checksum and the checksum of everything it depends on are unchanged. The "retrieving" message goes through Printer.Inform, so it is visible only with /trace:

# Test/snapshots/Snapshots1.v{0,1,2}.bpl from Boogie's own test suite

boogie /verifySnapshots:2 /trace Snapshots1.bpl | grep -E 'Verifying|Retrieving|finished'

Verifying P1 ...

Verifying P2 ...

Boogie program verifier finished with 1 verified, 1 error

Retrieving cached verification result for implementation P1...

Verifying P2 ...

Boogie program verifier finished with 1 verified, 1 error

Verifying P1 ...

Verifying P2 ...

Boogie program verifier finished with 1 verified, 1 error

15.13.2 /traceCaching🔗

Level

  

Meaning

0

  

nothing (default)

1

  

"for testing": log every cache action applied to a command

2

  

"for benchmarking": CSV statistics per request

3

  

both, plus debugging output

Level 1 names each transformation applied to a command. The interesting entries appear on the snapshot that actually has cached facts to inject:

boogie /verifySnapshots:2 /traceCaching:1 Snapshots1.bpl | grep -A1 'Processing'

Processing command (at Snapshots1.v0.bpl(13,5)) assert 1 != 1;

  >>> DoNothingToAssert

--

Processing command (at Snapshots1.v1.bpl(13,5)) assert 2 != 2;

  >>> DoNothingToAssert

--

Processing call to procedure P2 in implementation P1 (at Snapshots1.v2.bpl(5,5)):

  >>> added after: a##cached##0 := a##cached##0 && true;

Processing implementation P2 (at Snapshots1.v2.bpl(12,51)):

  >>> added after assuming the current precondition: a##cached##0 := a##cached##0 && true;

Processing command (at Snapshots1.v2.bpl(5,5)) assert false;

  >>> DoNothingToAssert

Processing command (at <unknown location>) a##cached##0 := a##cached##0 && true;

  >>> AssumeNegationOfAssumptionVariable

--

Processing command (at Snapshots1.v2.bpl(14,5)) assert 2 != 2;

  >>> DoNothingToAssert

Level 2 emits two CSV tables after each snapshot, and the tables are cumulative: one row per request seen so far. This is the pair printed after the second snapshot of Snapshots1 (the Time (ms) columns vary from run to run):

Cached verification result injector statistics as CSV:

Request ID, Transformed, Low, Medium, High, Skipped, Time (ms)

auto_request_id_1  ,   0,   0,   0,   0,   0,        0

auto_request_id_2  ,   1,   0,   1,   0,   1,        2

 

Statistics per request as CSV:

Request ID, Time (ms), Error, E (C), Inconclusive, I (C), Out of Memory, OoM (C), Timeout, T (C), Verified, V (C), DoNothingToAssert, MarkAsPartiallyVerified, MarkAsFullyVerified, RecycleError, AssumeNegationOfAssumptionVariable, DropAssume

auto_request_id_1  ,      123,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,   1,   0,   0,   0,   0,   0

auto_request_id_2  ,       19,  1,  0,  0,  0,  0,  0,  0,  0,  1,  1,   1,   0,   0,   0,   0,   0

 

Total time (ms) since first request: 156

The (C) columns count cached outcomes: auto_request_id_2 has V (C) = 1, one verification result taken from the cache.

/traceCaching is only meaningful together with /verifySnapshots.

15.14 Civl🔗

Option

  

Argument

  

Default

  

Skips

/trustMoverTypes

  

none

  

off

  

commutativity (mover) checks

/trustInvariants

  

none

  

off

  

yield-invariant checks

/trustRefinement

  

none

  

off

  

refinement checks and action refinement

/trustNoninterference

  

none

  

off

  

noninterference instrumentation

/trustLayersUpto:n

  

integer

  

-1

  

all checks at layers <= n

/trustLayersDownto:n

  

integer

  

int.MaxValue

  

all checks at layers >= n

/civlDesugaredFile:file

  

file name

  

off

  

---

/warnNotEliminatedVars

  

none

  

off

  

---

The /trust* options remove classes of generated proof obligations. They are for triage — narrowing down which check is failing, or getting a large development to run while one part is being reworked — and each one makes the result unsound with respect to the check it removes.

var {:layer 0,2} x: int;

 

right action {:layer 1,2} AtomicIncr()

modifies x;

{

  x := x + 1;

}

 

yield procedure {:layer 0} Incr();

refines AtomicIncr;

 

atomic action {:layer 2,2} AtomicIncrTwice()

modifies x;

{

  x := x + 2;

}

 

yield procedure {:layer 1} IncrTwice()

refines AtomicIncrTwice;

{

  call Incr();

  call Incr();

}

boogie /trace cli-civl.bpl | grep -E 'Verifying|finished'

Verifying Civl_CommutativityChecker_AtomicIncr_AtomicIncrTwice ...

Verifying Civl_IncrTwice_1 ...

Verifying Civl_IncrTwice_Refine_1 ...

Boogie program verifier finished with 3 verified, 0 errors

boogie /trace /trustMoverTypes cli-civl.bpl   | grep -E 'Verifying|finished'

boogie /trace /trustRefinement cli-civl.bpl   | grep -E 'Verifying|finished'

boogie /trace /trustLayersUpto:1 cli-civl.bpl | grep -E 'Verifying|finished'

Verifying Civl_IncrTwice_1 ...

Verifying Civl_IncrTwice_Refine_1 ...

Boogie program verifier finished with 2 verified, 0 errors

 

Verifying Civl_CommutativityChecker_AtomicIncr_AtomicIncrTwice ...

Verifying Civl_IncrTwice_1 ...

Boogie program verifier finished with 2 verified, 0 errors

 

Verifying Civl_CommutativityChecker_AtomicIncr_AtomicIncrTwice ...

Boogie program verifier finished with 1 verified, 0 errors

The layer options are applied in YieldingProcChecker as TrustLayersDownto <= layerNum || layerNum <= TrustLayersUpto, so they suppress the per-layer yielding-procedure and refinement checkers but not the commutativity checkers, which are not attached to a single layer. That is why /trustLayersUpto:1 above leaves the commutativity check in place.

/civlDesugaredFile:file writes the plain Boogie program that Civl rewriting produced — the whole encoding, including the parts pulled in from base. It forces unstructured printing while it writes and restores the previous setting afterwards. Expect a large file: the small example above desugars to 491 lines.

/warnNotEliminatedVars is undocumented. During transition-relation computation Civl tries to eliminate intermediate variables; with this flag TransitionRelationComputation.AddPath emits a warning of the form "<prefix>: could not eliminate variables {v, w, ...} on some path" for each path where some remained.

On a larger example the trust options are easier to weigh. Boogie’s own Test/civl/samples/2pc.bpl generates 8 checks by default; /trustRefinement leaves 7, /trustInvariants 5, /trustMoverTypes 4, /trustLayersUpto:1 4 and /trustLayersDownto:1 4. /trustNoninterference leaves all 8 — it does not remove checkers, it changes how yielding procedures are instrumented, so the count is unchanged while the obligations inside are weaker.

Remember that any Civl attribute in the program implicitly turns on /lib:base and /inferModifies.

15.15 Verbosity, tracing and debugging🔗

15.15.1 Verbosity levels🔗

Verbosity is a four-valued enum, default Normal. Three flags move it:

Option

  

Level

  

Trailer

  

Errors

  

Progress

/silent

  

Silent

  

no

  

no

  

no

/quiet

  

Quiet

  

no

  

yes

  

no

(none)

  

Normal

  

yes

  

yes

  

no

/trace

  

Trace

  

yes

  

yes

  

yes

The flags are not exclusive; the last one on the command line wins, since each simply assigns to Verbosity.

boogie /quiet cli-abs.bpl

cli-abs.bpl(11,1): Error: a postcondition could not be proved on this return path

cli-abs.bpl(8,3): Related location: this is the postcondition that could not be proved

Execution trace:

    cli-abs.bpl(10,5): anon0

boogie /silent cli-abs.bpl ; echo "exit=$?"

exit=0

/silent on a failing program produces no output and exit code 0 — there is no way to tell the run apart from a success without /xml.

15.15.2 /trace and friends🔗

Option

  

Effect

/trace

  

Per-phase progress, per-implementation timings, resource counts, split progress, and (as a side effect) BoogieDebug.DoPrinting = true.

/traceTimes

  

Elapsed time at fixed pipeline points.

/tracePOs

  

Proof-obligation counts per implementation. Also enables the Inform channel, so the "Verifying X ..." lines appear without /trace.

/traceverify

  

Dump the program at each stage of VC generation. Very verbose.

boogie /trace cli-small.bpl

Parsing cli-small.bpl

Coalescing blocks...

Inlining...

 

Verifying Abs ...

[TRACE] Using prover: z3

  [0.026 s, solver resource count: 700, 1 proof obligation]  verified

 

Boogie program verifier finished with 1 verified, 0 errors

boogie /traceTimes cli-small.bpl

>>> Becoming sentient   [-4.61E-05 s]

>>> Starting resolution   [0.0249093 s]

>>> Starting typechecking   [0.0378237 s]

>>> Starting implementation verification   [0.0857793 s]

>>> Starting live variable analysis   [0.0938588 s]

>>> Finished implementation verification   [0.1856154 s]

 

Boogie program verifier finished with 1 verified, 0 errors

Times are measured against Helpers.StartUp, a static field initialised the first time Helpers is touched. Since that happens inside the first ExtraTraceInformation call, the first figure is a small negative number.

boogie /tracePOs cli-abs.bpl

 

Verifying Abs ...

  [1 proof obligation]  verified

 

Verifying Bad ...

  [1 proof obligation]  error

cli-abs.bpl(11,1): Error: a postcondition could not be proved on this return path

cli-abs.bpl(8,3): Related location: this is the postcondition that could not be proved

Execution trace:

    cli-abs.bpl(10,5): anon0

 

Boogie program verifier finished with 1 verified, 1 error

/traceverify dumps the implementation at each stage of VC generation. Even on the one-procedure program above it produces 204 lines, beginning:

boogie /traceverify cli-small.bpl | head -6

Desugaring of lambda expressions produced 0 functions and 0 axioms:

original implementation

implementation Abs(x: int) returns (r: int)

{

 

  anon0:

15.16 Options with no effect, and undocumented options🔗

15.16.1 Options with no effect🔗

Option

  

Why

/vcBrackets:b

  

BracketIdsInVC has no reader.

/reflectAdd

  

Only VCExprASTPrinter consults it; the SMT-LIB lineariser does not.

/boolControlVC

  

Stratified inlining only, which the Boogie CLI cannot enable.

/useProverEvaluate

  

The evaluation path is used by Corral; in Boogie it only forces model production.

15.16.2 Undocumented options🔗

The following are accepted but do not appear in /help. They are documented above, in their functional sections.

Group

  

Options

General

  

/?, /launch

Printing

  

/printSplit, /printSplitDeclarations, /printLean

Prover

  

/proverPreamble, /enableUnSatCoreExtraction, /useProverEvaluate, /boolControlVC

Limits

  

/processTimeLimit, /timeLimitPerAssertionInPercent, /runDiagnosticsOnTimeout, /traceDiagnosticsOnTimeout

VC generation

  

/noPruneInfeasibleEdges, /deterministicExtractLoops, /randomSeedIterations

Inference

  

/inlineDepth, /printAssignment, /explainHoudini, /reverseHoudiniWorklist, /crossDependencies, /useUnsatCoreForContractInfer, /dbgRefuted, /stagedHoudini, /stagedHoudiniThreads, /stagedHoudiniReachabilityAnalysis, /stagedHoudiniMergeIgnoredAnnotations, /debugStagedHoudini, /concurrentHoudini, /modifyTopologicalSorting, /debugConcurrentHoudini, /variableDependenceIgnore

Civl

  

/warnNotEliminatedVars

15.17 Complete option index🔗

Every option name the parser recognises, with its argument shape and the default value of the field it sets. flag means a boolean switch that takes no argument.

Option

  

Argument

  

Default

  

Section

/?

  

flag

  

  

Informational options

/alwaysAssumeFreeLoopInvariants

  

flag

  

off

  

Verification-condition generation

/attrHelp

  

flag

  

  

Informational options

/boolControlVC

  

flag

  

off

  

Prover selection and options

/break

  

flag

  

  

Informational options

/checkInfer

  

flag

  

off

  

Inference

/civlDesugaredFile:file

  

file

  

off

  

Civl

/coalesceBlocks:c

  

0/1

  

1

  

Verification-condition generation

/concurrentHoudini

  

flag

  

off

  

Inference

/contractInfer

  

flag

  

off

  

Inference

/crossDependencies

  

flag

  

off

  

Inference

/dbgRefuted

  

flag

  

off

  

Inference

/debugConcurrentHoudini

  

flag

  

off

  

Inference

/debugStagedHoudini

  

flag

  

off

  

Inference

/deterministicExtractLoops

  

flag

  

off

  

Inlining and loops

/emitDebugInformation:n

  

0/1

  

1

  

Verification-condition generation

/enableUnSatCoreExtraction:n

  

int

  

0

  

Prover selection and options

/enhancedErrorMessages:n

  

0/1

  

0

  

Error reporting

/env:n

  

0/1/2

  

1

  

Informational options

/errorLimit:n

  

int

  

5

  

Error reporting

/errorTrace:n

  

0/1/2

  

1

  

Error reporting

/explainHoudini

  

flag

  

off

  

Inference

/extractLoops

  

flag

  

off

  

Inlining and loops

/forceBplErrors

  

flag

  

off

  

Error reporting

/freeVarLambdaLifting

  

flag

  

off

  

Inlining and loops

/help

  

flag

  

  

Informational options

/infer:flags

  

flag string

  

off

  

Inference

/inferModifies

  

flag

  

off

  

Verification-condition generation

/inline:i

  

none/assume/assert/spec

  

assume

  

Inlining and loops

/inlineDepth:n

  

int

  

-1

  

Inference

/instrumentInfer:c

  

h/e

  

h

  

Inference

/kInductionDepth:k

  

int

  

-1

  

Inlining and loops

/launch

  

flag

  

  

Informational options

/keepQuantifier

  

flag

  

off

  

Verification-condition generation

/lib:name

  

library name

  

none

  

Libraries

/liveVariableAnalysis:c

  

0/1/2

  

1

  

Verification-condition generation

/logPrefix:str

  

string

  

empty

  

File-name macros and /logPrefix

/loopUnroll:n

  

int

  

-1

  

Inlining and loops

/modifyTopologicalSorting

  

flag

  

off

  

Inference

/mv:file

  

file

  

off

  

Error reporting

/noProc:p

  

pattern

  

none

  

Selecting what to verify

/noPruneInfeasibleEdges

  

flag

  

pruning on

  

Verification-condition generation

/noResolve

  

flag

  

off

  

Selecting what to verify

/noTypecheck

  

flag

  

off

  

Selecting what to verify

/noVerify

  

flag

  

off

  

Selecting what to verify

/normalizeDeclarationOrder:n

  

0/1

  

1

  

Verification-condition generation

/normalizeNames:n

  

0/1

  

0

  

Verification-condition generation

/overlookTypeErrors

  

flag

  

off

  

Selecting what to verify

/p:KEY

  

prover option

  

none

  

Prover selection and options

/pretty:n

  

0/1

  

1

  

Printing the program

/print:file

  

file or -

  

off

  

Printing the program

/printAssignment

  

flag

  

off

  

Inference

/printCFG:prefix

  

prefix

  

off

  

Printing the program

/printDesugared

  

flag

  

off

  

Printing the program

/printInlined

  

flag

  

off

  

Inlining and loops

/printInstrumented

  

flag

  

off

  

Inference

/printLambdaLifting

  

flag

  

off

  

Inlining and loops

/printLean:file

  

file

  

off

  

Printing the program

/printMeasureDesugaring

  

flag

  

off

  

Inlining and loops

/printModel:n

  

0/1

  

0

  

Error reporting

/printModelToFile:file

  

file

  

off

  

Error reporting

/printPassive:file

  

file

  

off

  

/printPassive

/printPruned:prefix

  

prefix or -

  

off

  

Printing the program

/printSplit:prefix

  

prefix or -

  

off

  

Printing the program

/printSplitDeclarations

  

flag

  

off

  

Printing the program

/printUnstructured

  

flag

  

off

  

Printing the program

/printVerifiedProceduresCount:n

  

0/1

  

1

  

Printing the program

/printWithUniqueIds

  

flag

  

off

  

Printing the program

/proc:p

  

pattern

  

none

  

Selecting what to verify

/processTimeLimit:n

  

uint seconds

  

0

  

Resource limits

/proverDll:tp

  

name or path

  

SMTLib

  

Prover selection and options

/proverHelp

  

flag

  

  

Informational options

/proverLog:file

  

file

  

off

  

Prover selection and options

/proverLogAppend

  

flag

  

off

  

Prover selection and options

/proverOpt:KEY

  

prover option

  

none

  

Prover selection and options

/proverPreamble:file

  

file

  

off

  

Prover selection and options

/proverWarnings:n

  

0/1/2

  

0

  

Prover selection and options

/prune:n

  

0/1

  

0

  

/prune

/quiet

  

flag

  

  

Verbosity, tracing and debugging

/randomizeVcIterations:n

  

int >= 1

  

1

  

Verification-condition generation

/randomSeed:s

  

int

  

unset

  

Verification-condition generation

/randomSeedIterations:n

  

int >= 1

  

1

  

Verification-condition generation

/reflectAdd

  

flag

  

off

  

Verification-condition generation

/relaxFocus

  

flag

  

off

  

Splitting and parallelism

/removeEmptyBlocks:c

  

0/1

  

1

  

Verification-condition generation

/restartProver

  

flag

  

off

  

Prover selection and options

/reverseHoudiniWorklist

  

flag

  

off

  

Inference

/rlimit:n

  

uint

  

0

  

Resource limits

/runDiagnosticsOnTimeout

  

flag

  

off

  

Resource limits

/silent

  

flag

  

  

Verbosity, tracing and debugging

/smoke

  

flag

  

off

  

Error reporting

/smokeTimeout:n

  

uint seconds

  

10

  

Error reporting

/soundLoopUnrolling

  

flag

  

off

  

Inlining and loops

/stagedHoudini:s

  

COARSE/FINE/BALANCED

  

off

  

Inference

/stagedHoudiniMergeIgnoredAnnotations

  

flag

  

off

  

Inference

/stagedHoudiniReachabilityAnalysis

  

flag

  

off

  

Inference

/stagedHoudiniThreads:n

  

int

  

1

  

Inference

/subsumption:c

  

0/1/2

  

2

  

Verification-condition generation

/timeLimit:n

  

uint seconds

  

0

  

Resource limits

/timeLimitPerAssertionInPercent:n

  

uint > 0

  

10

  

Resource limits

/trace

  

flag

  

  

Verbosity, tracing and debugging

/traceCaching:n

  

0..3

  

0

  

Caching and snapshots

/traceDiagnosticsOnTimeout

  

flag

  

off

  

Resource limits

/tracePOs

  

flag

  

off

  

Verbosity, tracing and debugging

/traceTimes

  

flag

  

off

  

Verbosity, tracing and debugging

/traceverify

  

flag

  

off

  

Verbosity, tracing and debugging

/trackVerificationCoverage

  

flag

  

off

  

Error reporting

/trustInvariants

  

flag

  

off

  

Civl

/trustLayersDownto:n

  

int

  

int.MaxValue

  

Civl

/trustLayersUpto:n

  

int

  

-1

  

Civl

/trustMoverTypes

  

flag

  

off

  

Civl

/trustNoninterference

  

flag

  

off

  

Civl

/trustRefinement

  

flag

  

off

  

Civl

/typeEncoding:t

  

m/p/a

  

m

  

Verification-condition generation

/useArrayAxioms

  

flag

  

off

  

Verification-condition generation

/useBaseNameForFileName

  

flag

  

off

  

Printing the program

/useProverEvaluate

  

flag

  

off

  

Prover selection and options

/useUnsatCoreForContractInfer

  

flag

  

off

  

Inference

/variableDependenceIgnore:file

  

file

  

off

  

Inference

/vcBrackets:b

  

0/1

  

-1

  

Prover selection and options

/vcsAssumeMult:f

  

double

  

0.01

  

Splitting and parallelism

/vcsCores:n

  

int >= 1

  

1

  

Splitting and parallelism

/vcsDumpSplits

  

flag

  

off

  

Splitting and parallelism

/vcsFinalAssertTimeout:n

  

uint seconds

  

30

  

Splitting and parallelism

/vcsKeepGoingTimeout:n

  

uint seconds

  

1

  

Splitting and parallelism

/vcsLoad:f

  

double < 3.0

  

  

Splitting and parallelism

/vcsMaxCost:f

  

double

  

1.0

  

/vcsMaxCost

/vcsMaxKeepGoingSplits:n

  

int

  

1

  

Splitting and parallelism

/vcsMaxSplits:n

  

int

  

1

  

Splitting and parallelism

/vcsPathCostMult:f

  

double

  

1.0

  

Splitting and parallelism

/vcsPathJoinMult:f

  

double

  

0.8

  

Splitting and parallelism

/vcsPathSplitMult:f

  

double

  

0.5

  

Splitting and parallelism

/vcsSplitOnEveryAssert

  

flag

  

off

  

Splitting and parallelism

/verifySeparately

  

flag

  

off

  

Selecting what to verify

/verifySnapshots:n

  

0..3

  

-1

  

Caching and snapshots

/version

  

flag

  

  

Informational options

/wait

  

flag

  

off

  

Informational options

/warnNotEliminatedVars

  

flag

  

off

  

Civl

/warnVacuousProofs

  

flag

  

off

  

Error reporting

/xml:file

  

file

  

off

  

Printing the program