Releases: GaloisInc/saw-script
Release list
v.1.5.1
Version 1.5.1 -- 2026-05-22
This release adds experimental support for translating Cryptol modules into Isabelle theories, with limited support for translating SAWCore terms. See saw-core-isabelle/README.md.
New Features
-
SAW now has the following commands for generating Isabelle theories (requires
enable_experimental):write_isabelle_cryptol_modulesfor translating Cryptol modulesoffline_isabellefor translating SAW subgoalswrite_isabelle_termfor translating SAWCore terms
Supporting theories are in
saw-core-isabelle/isabelle/theories.Additionally, the release includes a standalone binary
cryptol-to-isabellefor translating Cryptol modules into Isabelle theories.
v1.5
Version 1.5 -- 2026-01-31
This release supports version 8 of mir-json's schema.
Changes
mir_verifynow enforces correctness checks that match the existing behavior ofllvm_verifyandjvm_verify:
-
Omitting a call to
mir_execute_funcor callingmir_execute_funcmultiple times will cause SAW to raise an error. -
For functions that return a value other than
(), amir_returnstatement is now required. Omitting the return statement will cause SAW to raise an error.
- The (by now extremely old)
crucible_*alternate names for thellvm_*primitives have been marked deprecated and will now warn. They are expected to be hidden by default in SAW 1.6.
Some of these had been previously still marked experimental; they have been marked deprecated and hidden by default. They are expected to be removed in SAW 1.6.
Relatedly, the type SetupValue has been replaced by LLVMValue. However, because this change is comparatively recent, uses of SetupValue will not warn yet in this release.
-
The
boolectorandcvc4solver command families have been marked deprecated. Boolector has been replaced upstream by Bitwuzla, and CVC4 is an outdated version of CVC5, and proofs should be updated accordingly. If you encounter a proof that works with Boolector and not Bitwuzla, or with CVC4 and not CVC5, please file an issue. -
The following deprecated SAWScript builtins have been removed: -
addsimp'-addsimps'-crucible_setup_val_to_term -
The following deprecated SAWScript builtins are now hidden by default: -
env
llvm_struct was also scheduled to be hidden in 1.5; this has been postponed to 1.6 for internal reasons.
-
The following solver builtins / proof tactics have been renamed for consistency. The old names remain but have been marked deprecated. -
external_aig_solver->arbitrary_aig-external_cnf_solver->arbitrary_cnf-w4_offline_smtlib2->offline_w4_smtlib2-write_smtlib2_w4->write_w4_smtlib2 -
Binary builds have been moved up to GHC 9.6 from 9.4.
-
Renamed
coqin command names torocqand removed experimental status. The old command names will continue to work but have been deprecated. -write_coq_termis nowwrite_rocq_term. -write_coq_cryptol_moduleis nowwrite_rocq_cryptol_module. -write_coq_sawcore_preludeis nowwrite_rocq_sawcore_prelude. -write_coq_cryptol_primitives_for_sawcoreis nowwrite_rocq_cryptol_primitives_for_sawcore. -offline_coqis nowoffline_rocq. -
MIR verification is no longer tagged experimental.
-
SAW no longer timestamps (some of) its output by default. If you want the timestamps back, pass the -T option on the command line. For more effective timing (e.g. for benchmarking) use the
timeorwith_timeSAWScript builtins, or time the whole run of the executable with external tools, as needed. -
The REPL no longer gratuitously rejects multiple statements separated by semicolons on a single line. It also no longer chokes on lines that contain only comments.
-
SAWScript files can now be included with
include_onceas well as plaininclude. Aninclude_oncewill do nothing if the same file has already been included. The concept of "same" used is the same pathname -- the check does not chase symbolic links or consult OS-level file identity markers. -
The
includefunctionality in SAWScript is now syntax rather than a builtin function. This means thatincludeis now a reserved word, and assorted wild things that used to be theoretically possible (like producing a monad action that might be an include and might be something else) are not allowed. Computing the filename to include is also no longer permitted. (Since SAW has negligible ability to compute strings, it is highly unlikely anyone was doing this.) More importantlyincludeis no longer a back door to the type system. Also on the plus side, you can now successfullyincludein the ProofScript context. There is a small functional difference, which is that includes are now resolved up front before execution begins, instead of when the include statements are reached. If anyone has a use case that this affects, please get in touch. -
The
SetupValueassociated with LLVM verification has been renamed toLLVMValueto match the correspondingJVMValueandMIRValuetypes. The nameSetupValueremains as an alias. Eventually it will be marked deprecated, but probably not until at least after the next release. -
The
LLVMSetupandMIRSetupmonad types are now just ordinary builtin types; their names are no longer reserved words. (TheJVMSetuptype was already this way. A bogus unusedJavaSetupreserved word has been removed. See #2768.) The legacy nameCrucibleSetupremains a reserved word for the time being. -
The REPL's
:searchcommand can now handle unapplied type constructors. For example, one can now write:search ProofScriptto find objects mentioningProofScriptapplied to any type. -
llvm_verifynow enforces that anllvm_returnspecification is included for any function with a non-void return type. To write a spec that asserts nothing about the return value,llvm_returnmay be used with a fresh variable declared withllvm_fresh_varin the post-state section, like this:
do { ... llvm_execute_func ; ... ret <- llvm_fresh_var "ret" ; llvm_return (llvm_term ret); }
-
jvm_verifynow enforces that ajvm_returnspecification is included for any method with a non-void return type. To write a spec that asserts nothing about the return value,jvm_returnmay be used with a fresh variable declared withjvm_fresh_varin the post-state section. -
The
cryptol_loadandcryptol_primscommands now fail if used in a nested scope, instead of behaving strangely. -
The old behavior of SAWScript where top-level names could be arbitrarily rebound, such that existing uses would see the updated value, has been superseded. Among other problems, it wasn't type safe. Now, rebinding a variable creates a new variable that hides the old one; prior references are not affected.
Substitute functionality for the old behavior is now available by using the new syntax let rebindable. After let rebindable x = 3, x is mutable and a subsequent let rebindable x = 4 will change the value seen by all uses. The value type must remain the same; to avoid unnecessary complexity, polymorphic values cannot be rebound. Participants in mutually recursive declarations defined with rec (rather than let) cannot be rebound. This is only allowed at the syntactic top level, and not within functions, do-blocks, or expressions. See issue #1646 for further information/discussion.
Note that rebindable is now a reserved word.
-
In SAWCore syntax (as used by
parse_core,prove_core, andread_core) partially-applied recursors are no longer an error. Elimination sorts for recursors are now specified by suffix:TypeName#indeliminates toProp,TypeName#receliminates tosort 0, andTypeName#rec<n>eliminates tosort n. -
The experimental command
extract_uninterphas been removed. -
The
normalize_term_opaqueandgoal_normalizecommands have been reimplemented using a different normalization strategy which is more conservative about type safety. They may produce different outputs than before; in particular, fewer applications of primitive functions are reduced. -
The deprecated Heapster, MRSolver, and Monadify features have been removed. The following SAW commands and types are no longer available:
- HeapsterEnv (type) - Refnset (type) - write_coq_cryptol_module_monadic - mrsolver_set_debug_level - mrsolver_set_debug_printing_depth - mrsolver - empty_rs - addrefn - addrefns - mrsolver_with - refines - monadify_term - set_monadification - heapster_init_env - heapster_init_env_debug - heapster_init_env_from_file - heapster_init_env_from_file_debug - heapster_init_env_for_files - heapster_init_env_for_files_debug - heapster_get_cfg - heapster_define_opaque_perm - heapster_define_recursive_perm - heapster_define_reachability_perm - heapster_define_recursive_shape - heapster_define_perm - heapster_define_llvmshape - heapster_define_opaque_llvmshape - heapster_define_rust_type - heapster_define_rust_type_qual - heapster_block_entry_hint - heapster_gen_block_perms_hint - heapster_join_point_hint - heapster_find_symbol - heapster_find_symbols - heapster_find_symbol_with_type - heapster_find_symbols_with_type - heapster_find_symbol_commands - heapster_find_trait_method_symbol - heapster_assume_fun - heapster_assume_fun_rename - heapster_assume_fun_rename_prim - heapster_assume_fun_multi - heapster_typecheck_fun - heapster_typecheck_fun_rename - heapster_typecheck_mut_funs - heapster_set_event_type - heapster_print_fun_trans - heapster_export_coq - heapster_set_debug_level - heapster_set_translation_checks - heapster_trans_rust_type - heapster_parse_test - heapster_dump_ide_info
-
Function
write_coq_cryptol_primitives_for_sawcoreno longer generates Coq translations of SAWCore modulesSpecM.sawcoreandCryptolM.sawcore, which have been removed. Accordingly, the second and thirdStringarguments towrite_coq_cryptol_primitives_for_sawcorehave been removed. -
The behavior of
cryptol_loadhas changed; previously when we had this
A <- cryptol_load "A1.cry" -- A1::** are added to {{A::}} A <- cryptol_load "A2.cry" -- A2:: are added to {{A::**}}
the A in 2nd line would shadow the first A, and for each symbol s from "A2.cry", that symbol may shadow any duplicate symbol s from "A1.cry" and this would also leave symbols from "A1.cry" in the Cryptol environment.
The new behavior is that the same two commands now work identically to the following
import "A.cry" as A import "A2.cry" as A
and as a result - no sh...
v1.4
Version 1.4 -- 2025-11-18
This release supports version 4 of mir-json's schema.
The saw executable's command-line handling has been changed to permit passing arguments to SAWScript scripts. Words on the command line following the script name are treated as arguments to the script and not interpreted by saw. The behavior of the get_opt SAWScript builtin has changed accordingly; it now retrieves these arguments (with the 0th being the script name) instead of saw's own command line arguments. This is a breaking change in two ways:
- Options intended for
sawbut passed after the script name will no longer be recognized. get_optwill essentially always return different strings from what it did in previous versions.
Aget_noptsbuiltin has also been added to allow retrieving the number of arguments. These changes bringsawinto line with the way other interpreters handle script arguments.
The way git information gets compiled in (so it can be reported with e.g. saw --version) has been changed. You must build with build.sh after git changes for those changes to show through; builds done directly with cabal will not update the git info. (If you really want you can run the update script by hand instead, of course.) Note that build.sh is in any case the recommended way to build.
build.sh now accepts the -j option to control parallelism (which is passed through to cabal build). Note that typical installations of cabal configure themselves to use the number of CPUs for this, even though the cabal documentation says that the default is 1. Also, the semaphore-based build coordination in GHC 9.8 and up is now enabled by default. (It is enabled unconditionally; cabal ignores it when using earlier GHC versions.)
The names of the various test suites used with cabal test have been normalized. See saw.cabal for the full list. The most notable changes are:
- the main test suite, which people occasionally run directly, is now spelled
integration-testswith a dash rather thanintegration_testswith an underscore; - the crux-mir-comp test suite is now called
crux-mir-comp-testsrather than justtest.
SAW binary distributions now include the crux-mir-comp tool under bin/. crux-mir-comp is a Crux frontend for MIR in the style of crux-mir, but extended with the ability to support compositional verification using techniques similar to SAW.
New Features
-
There is now a
get_envSAWScript builtin for inspecting the process environment. -
SAW now supports importing Cryptol code that uses enums.
-
One missing feature is supporting case default alternatives where we bind the whole scrutinee, such as this example:
case s of C1 ... -> EXP1 y -> EXP2 -- 'y' is free in EXP2This, more conventional default alternative, is supported:
case s of C1 ... -> EXP1 _ -> EXP2 -- '_' is not used.And case expressions that don't need a default case are supported.
-
-
SAW now ships with a
hie.yamlfile for haskell-language-server. -
Add new SAWScript commands
term_evalandterm_eval_unint. These are likegoal_evalandgoal_eval_unintproof tactics but work on arbitrary terms rather than proof goals. -
Add new SAWScript MIR commands
mir_elem_valueandmir_elem_reffor indexing into arrays and references to arrays. -
Add a new SAWScript MIR command
mir_vec_offor creating RustVecvalues in specifications. -
Support writing MIR specifications involving raw pointers. This is done with the new SAWScript commands
mir_raw_ptr_const,mir_raw_ptr_mut,mir_alloc_raw_ptr_const, andmir_alloc_raw_ptr_mut, which are similar to the existingmir_ref,mir_ref_mut,mir_alloc, andmir_alloc_mutcommands for reference types. There is alsomir_cast_raw_ptr. -
Support writing MIR specifications involving raw pointers to contiguous sequences of multiple values, with the new SAWScript commands
mir_alloc_raw_ptr_const_multi,mir_alloc_raw_ptr_mut_multi, andmir_points_to_multi. -
Support
bmuxgates in exported Yosys directly to avoid reliance onbmuxmap -
Vacuity checking (
--detect-vacuity) now correctly reports contradictions in specifications for all Crucible backends: LLVM, MIR, and JVM. Previously, vacuous proofs in MIR and JVM code could go undetected. -
Support verifying Rust code up to version 1.86.
-
Added
mir_ref_ofandmir_ref_of_mutto SAWScript's MIR support. These helpers combinemir_alloc/mir_alloc_mutandmir_points_to, simplifying the common pattern of allocating a reference and immediately initializing it.
Bug fixes
-
We now initialize Java on demand, instead of when starting SAW. This makes it possible to run SAW on systems without a functional Java installation (e.g., it would appear that
javaon Mac OS is missing a runtime by default). -
A number of SAWScript builtins were found to have wrong return types declared. These have been corrected; minor adjustments to existing code might be needed. (Any actual use of the returned values would have triggered a panic and been noticed.) The affected builtins:
approxmcheapster_assume_fun_multiheapster_assume_fun_rename_primheapster_assume_fun_renameheapster_assume_funheapster_define_llvmshapeheapster_define_opaque_llvmshapeheapster_define_opaque_permheapster_define_permheapster_define_reachability_permheapster_define_recursive_permheapster_define_recursive_shapeheapster_define_rust_type_qualheapster_define_rust_typeheapster_find_symbol_commandsset_monadification
-
The
headandtailprimitives are now implemented in the SAW-Core evaluator (#2312). -
Functions imported with
yosys_importnow use a non-reversed bit ordering. All bit indices in Yosys JSON files are now treated as indexing from the right. Arithmetic operations treat the right-most bit (Yosys index 0) as the least significant, and are translated without usingreverse. -
Invoking the Cryptol
errorfunction in SAW now preserves the error message instead of throwing it away. -
Fixed inconsistent type checking of
llvm_assert,mir_assert, and jvm_assertstatements. Previously, the LLVM backend implicitly rejected  predicates of non-Bit type due to evaluation failures, while MIR and JVM  backends accepted them, leading to backend-specific errors. -
The
mir_isizeandmir_usizetypes now correspond to the Cryptol type[64]instead of[32]. -
SAW's interpretation of signed integer division and modulus is now self-consistent and matches Cryptol. Previously, what you got depended on how and where the evaluation happened. Note however that the interpretation used by Cryptol (which rounds towards negative infinity) is not the same as that found in conventional CPUs and programming languages (which uses Euclidean division).
-
Fix SAW errors that could arise when producing models for sequence values (e.g., values of type
[2][8]) when using thesatorsat_printcommands.
Deprecations
-
The long-deprecated builtins
sbv_uninterpreted,read_sbv, and their typeUninterphave been, finally, removed. The deprecated builtinsaddsimp',addsimps', andcrucible_setup_val_to_typed_termremain for now but will be removed in the next release. -
The
envprimitive has been marked deprecated. Use the:envREPL command (or:search, which is typically more effective) instead. -
Heapster and Mr. Solver have been deprecated. They are now only available with
enable_deprecated(skipping ahead in the deprecation process) and will be removed in the next release. This affects theHeapsterEnvandRefnsettypes, all theheapster_*andmrsolver_*builtins, pluswrite_coq_cryptol_module_monadic,refines,monadify_term,set_monadification,empty_rs,addrefn, andaddrefns. -
The "highly experimental" SAWScript
callccbuiltin (an implementation of call-with-current-continuation) has been removed. Its behavior was, justifiably, described as "somewhat unpredictable," and the implementation internals were highly problematic. Furthermore, the one known use ever was for something that should have been done another way. -
It was previously possible to declare monadic values of an undocumented type
CryptolSetup tbut not do anything with them. This name is no longer magic. -
llvm_structhas been marked deprecated. It is the same asllvm_aliasand you should use this instead. (If you were looking for a function to create a struct type from its contents, that'sllvm_struct_type.)
v1.3
This release supports version 1 of mir-json's schema.
New Features
-
SAW documentation is now under a single Sphinx umbrella, resulting in a complete overhaul of the
doc/directory (#1723). Generally speaking, all content has stayed the same, and only organization has changed. Most importantly for users, the PDF artifacts included in CI-generated releases have different names and render with Sphinx styling. -
The contributor docs have been improved and modernized.
-
The saw executable now accepts a -B or --batch option to run a file of REPL commands, similar to the -b option in Cryptol.
-
Add a
bitwuzlafamily of proof scripts that use the Bitwuzla SMT solver. -
Add a
:searchREPL command, which searches the value environment by type. For example, to find everything involving the LLVMSetup monad you can do:search (LLVMSetup _). -
Add a
:tenvREPL command, which is like:envbut prints the type environment instead of the variable environment.:tis still short for:type. -
Add
mir_equalandjvm_equalcommands, which mirror thellvm_equalcommand for the MIR and JVM backends, respectively. -
Explicitly check that the
mir-jsonschema version is supported when parsing a MIR JSON file. If the version is not supported, it will be rejected. This helps ensure that unsupportedmir-jsonfiles do not cause unintended results. -
Emit a warning when parsing an LLVM bitcode metadata record that SAW does not support. (Previously, SAW would throw a fatal error if this occurred, so this change makes SAW more permissive with respect to unsupported LLVM versions.)
Bug fixes
-
An off-by-one error in
listSortDropin the SAWCore prelude has been fixed (#2241). -
git submodule update --init --recursive no longer causes an infinite checkout loop. (However, using --recursive clones a considerable number of unnecessary trees and is still not recommended.)
-
The saw executable's usage message now fits into a terminal. (#405)
-
Invalid verbosity level specifications passed to the saw executable's -v (SAWScript verbosity) and -d (simulator verbosity) options are now rejected. (The previous behavior for -v was to select maximum debug output. It is unclear what effect negative verbosity levels might have had with -d.)
-
SAW now accepts Unicode input beyond characters 0..255, including in embedded Cryptol fragments and saw-core modules, and allows the same Unicode code points in identifiers as Cryptol. It is thus now possible to refer to Cryptol objects whose names include extended characters. (#2042)
-
Function types in records no longer require gratuitous parentheses. (#1994)
-
Unexpected special-case type behavior of monad binds in the syntactic top level has been removed. (This was not specifically associated with the TopLevel monad, so top-level binds and binds in functions in TopLevel, or in nested do-blocks, would behave differently.) See issue #2162.
There are three primary visible consequences. The first is that the REPL no longer accepts non-monadic expressions. These can still be evaluated and printed; just prefix them with
return. (Affordances specifically for the REPL so this is not required there may be restored in the future.)The second is that statements of the form
x <- e;whereeis a pure (non-monadic) term used to be (improperly) accepted at the top level of scripts. These statements now generate a warning. This will become an error in a future release and such statements should be rewritten aslet x = e;. For example,t <- unfold_term ["reverse"] {{ reverse 0b01 }};should be changed tolet t = unfold_term ["reverse"] {{ reverse 0b01 }};.The third is that statements of the form
x <- s;or justs;wheresis a term in the wrong monad also used to be improperly accepted at the top level of scripts. These statements silently did nothing. They will now generate a warning. This will become an error in a future release. Such statements should be removed or rewritten. For example, it used to be possible to writellvm_assert {{ False }};at the top level (outside any specification) and it would be ignored.llvm_assertis only meaningful within an LLVM specification. -
A number of SAWScript type checking problems have been fixed, including issues #2077 and #2105. Some previously accepted scripts and specs may be rejected and need (generally minor) adjustment. Prior to these changes the typechecker allowed unbound type variables in a number of places (such as on the right-hand side of typedefs, and in function signatures), so for example type names containing typos would not necessarily have been caught and will now fail.
typedef t = nonexistentwas previously accepted and now is not. These problems could trigger panics, but there does not appear to have been any way to produce unsoundness in the sense of false verifications. -
Counterexamples including SMT arrays are now printed with the array contents instead of placeholder text.
-
Due to the regressions seen in issues #1946 and #1944, the experimental compositional hardware verification work has been reverted.
-
Fix a bug in which an LLVM override would fail to apply when matching an argument against a string constant.
-
Assorted other minor bugs and annoyances have been fixed, and a number of error messages have been improved, particularly type errors.
v1.2
New Features
-
Add
mir_str_slice_valueandmir_str_slice_range_valuefunctions, which
allow taking&strslices. For more information, see the documentation in the
SAW manual. -
Add
mir_mux_valuescommand for muxing two MIR values. -
Add support for GHC 9.8.
Bug fixes
-
Fix bug that caused MIR to incorrectly reject overrides with multiple const slice arguments
-
Error messages have been improved such that the locations printed with type errors and other diagnostics now have a much stronger connection with reality.
v1.1
New Features
-
SAW now supports loading and reasoning about Cryptol declarations that make use of numeric constraint guards. For more information on numeric constraint guards, see the relavent section of the Cryptol reference manual.
-
Add an experimental
mir_verifycommand, along with related utilities for constructing specifications for MIR/Rust programs. For more information, see themir_*commands documented in the SAW manual. -
SAW now supports importing Cryptol modules containing
foreigndeclarations. For more information, see the manual. -
Building on the above feature, SAW now supports automatically generating LLVM setup scripts for Cryptol FFI functions with the
llvm_ffi_setupcommand. For more information, see the manual. -
Ghost state is now supported with the JVM and MIR language backends:
- The
llvm_declare_ghost_statecommand is now deprecated in favor of the newdeclare_ghost_statecommand, as nothing about this command is LLVM-specific. - Add
jvm_ghost_valueandmir_ghost_valuecommands in addition to the existingllvm_ghost_valuecommand.
- The
-
SAW now includes an experimental
set_solver_cache_pathcommand, which caches the results of tactics which call out to automated provers. This can save a considerable amount of time when repeatedly running proof scripts. For more information, see the manual. -
Add experimental support for verifying hardware circuits via VHDL and Yosys. There is now a family of experimental
yosys_*commands that support this. For more information, see the manual. -
Extend
llvm_verify_x86in order to handle x86 functions that spill arguments to the stack.
Bug fixes
-
Fix a bug in which SAW failed to expand type synonyms used in the definition of another type synonym.
-
Fix a bug in which SAW would fail to load LLVM bitcode files produced by Apple Clang on macOS.
-
Overall, closed issues #1818, #1822, #1824, #1828, #1834, #1839, #1842, #1843, #1847, #1852, #1854, #1856, 1857, #1859, #1864, #1870, #1875, #1883, #1884, #1888, #1892, #1894, #1897, #1900, #1909, #1914, #1917, #1923, #1927, #1929, #1932, #1938, #1942, #1945, #1961, #1968, #1970, #1973, #1985, #2003, and #2005.
-
Overall, merged pull requests #1882, #1885, #1889, #1890, #1891, #1893, #1898, #1899, #1904, #1905, #1907, #1908, #1911, #1913, #1915, #1916, #1919, #1920, #1921, #1922, #1924, #1925, #1928, #1930, #1931, #1933, #1934, #1935, #1936, #1937, #1939, #1940, #1941, #1943, #1947, #1948, #1949, #1950, #1951, #1952, #1955, #1958, #1959, #1962, #1963, #1969, #1971, #1972, #1974, #1986, #1986, #1987, #1991, #1992, #1993, #2001, #2004, #2006, #2007, #2008, #2009, #2010, #2011, #2012, #2013, #2014, #2015, #2020, #2021, #2022, and #2024.
v1.0
New Features
-
SAW now implements Heapster, which allows extracting functional specifications of memory-safe C programs to Coq. There is now a family of experimental
heapster_*commands that support this. For more information, refer to the Heapster README. -
New commands
enable_what4_evalanddisable_what4_evalto enable or disable What4 translation for SAWCore expressions during Crucible symbolic execution. -
New command
llvm_alloc_sym_initlikellvm_alloc, but assume that the allocation is initialized with symbolic bytes. New commandsdisable_alloc_sym_init_checkandenable_alloc_sym_init_checkto disable or enable the allocation initialization check associated withllvm_alloc_sym_initduring override application. -
New command
set_crucible_timeoutto set the timeout for the SMT solver during the LLVM and X86 Crucible symbolic execution. This is used for path-sat checks, and sat checks when applying overrides. -
New command
w4_unint_z3_usinglikew4_unint_z3, but use the given Z3 tactic. -
A new
llvm_points_to_bitfieldcommand has been introduced, providing a version ofllvm_points_tothat is specifically tailored for structs containing bitfields. In order to usellvm_points_to_bitfield, one must also use the newenable_lax_loads_and_storescommand, which relaxes some of Crucible's assumptions about reading from uninitialized memory. (This command also comes with a correspondingdisable_lax_loads_and_storescommand.) For more details on how each of these commands should be used, consult the "Bitfields" section of the SAW manual. -
A new
llvm_cast_pointerfunction has been added that allows users to directly specify that a pointer should be treated as pointing to a particular type. This mainly affects the results of subsequentllvm_fieldandllvm_elemcalls. This is especially useful for dealing with Cuniontypes, as the type information provided by LLVM is imprecise in these cases. -
A new
llvm_unionfunction has been added that uses debug information to allow users to select fields fromuniontypes by name. This automates the process of manually applyingllvm_cast_pointerwith the type of the selected union field. Just as withllvm_field, debug symbols are required forllvm_unionto work correctly. -
A new highly experimental
llvm_verify_fixpoint_x86function that allows partial correctness verification of loops using loop invariants instead of full symbolic unrolling. Only certain very simple styles of loops can currently be accommodated, and the user is required to provide a term that describes how the live variables in the loop evolve over an iteration. -
A new experimental facility for "tagging" proof obligations in specifications and later using those tags to make decisions in proof tactics. See the new
llvm_setup_with_tag,goal_has_tags, andgoal_has_some_tagcommands. -
A new experimental option (toggled via
enable_single_override_special_caseanddisable_single_override_special_case) which changes the handling for cases where an overriden function has only one override that could possibly apply. When the special case handling is enabled, preconditions for the override are asserted separately, maintaining their individual metadata instead of being combined into a single precondition for the entire override. This may be advantageous if proving the individual goals is easier than the conjunction of all of them, or if different tactics are needed for different subgoals. Currently, this option only applies to LLVM verifications. -
Experimental interactive features. Using the new
subshellandproof_subshellcommands, a user can regain a command-line interface in the middle of a running script for experimentation and exploration purposes. In additioncallccandcheckpointallow the user to have more flexibility with restoring prior states and executing the remaining context of a proof in such an interactive session. -
A new experimental
llvm_verify_x86_with_invariantcommand that allows verification certain kinds of simple loops by using a user-provided loop invariant. -
Add a
cvc5family of proof scripts that use the CVC5 SMT solver. (Note that thesbv_cvc5andsbv_unint_cvc5are non-functional on Windows at this time due to a downstream issue with CVC5 1.0.4 and earlier.) -
Add experimental support for verifying Rust programs. For more information, see the
mir_*commands documented in the SAW manual.
Changes
-
A significant overhaul of the SAW proof and tactics system. Under the hood, tactics now manipulate sequents instead of just propositions. This allows more the user to specify more precise goal rearrangements, and provides a much nicer interface for proof exploration (especially with the new
proof_subshell). There are a variety of new tactics that provide the user with control over proof steps that is similar to that found in an interactive theorem prover. Proofs that do not make use of the new experimental tactics should see no substantive changes, so this is expected to be a highly backward-compatible change. -
The experimental and rarely-used
goal_assumetactic has been removed. The use case it was targeting is better solved via sequents. -
Support LLVM versions up to 16.
Bug fixes
-
Overall, closed issues #288, #300, #372, #415, #695, #705, #718, #722, #736, #737, #738, #739, #740, #1037, #1155, #1259, #1316, #1358, #1409, #1412, #1460, #1461, #1462, #1472, #1493, #1494, #1502, #1507, #1520, #1533, #1537, #1558, #1561, #1562, #1565, #1566, #1567, #1579, #1584, #1588, #1591, #1601, #1618, #1619, #1632, #1635, #1644, #1647, #1662, #1668, #1669, #1678, #1680, #1684, #1691, #1702, #1703, #1726, #1741, #1742, #1744, #1748, #1767, #1768, #1780, #1784, #1785, #1794, #1801, #1813, #1822, #1824, #1828, #1834, #1839, #1847, #1852, #1854, #1856, #1857, #1864, #1870, and #1875.
-
Overall, merged pull requests #378, #630, #651, #710, #712, #725, #753, #795, #802, #857, #859, #984, #1000, #1002, #1095, #1110, #1117, #1150, #1172, #1194, #1273, #1297, #1313, #1359, #1374, #1385, #1386, #1422, #1452, #1467, #1469, #1470, #1473, #1474, #1475, #1477, #1478, #1480, #1481, #1482, #1483, #1484, #1485, #1486, #1487, #1488, #1489, #1490, #1491, #1495, #1496, #1497, #1501, #1503, #1504, #1505, #1506, #1509, #1510, #1511, #1512, #1513, #1514, #1515, #1518, #1519, #1521, #1523, #1524, #1525, #1527, #1528, #1529, #1530, #1531, #1534, #1535, #1536, #1538, #1539, #1543, #1544, #1545, #1546, #1547, #1549, #1550, #1552, #1553, #1554, #1555, #1557, #1559, #1564, #1568, #1574, #1576, #1582, #1583, #1587, #1589, #1590, #1592, #1593, #1594, #1596, #1597, #1598, #1599, #1600, #1602, #1604, #1605, #1609, #1610, #1614, #1615, #1617, #1622, #1624, #1625, #1626, #1627, #1628, #1629, #1630, #1631, #1633, #1634, #1636, #1637, #1645, #1648, #1649, #1650, #1651, #1652, #1654, #1655, #1656, #1657, #1658, #1659, #1660, #1661, #1666, #1667, #1670, #1671, #1672, #1673, #1675, #1679, #1682, #1686, #1687, #1688, #1689, #1690, #1692, #1693, #1694, #1695, #1696, #1697, #1698, #1700, #1705, #1708, #1710, #1711, #1712, #1713, #1717, #1718, #1722, #1724, #1725, #1727, #1736, #1738, #1739, #1743, #1746, #1749, #1750, #1752, #1755, #1756, #1757, #1769, #1770, #1771, #1773, #1774, #1775, #1776, #1777, #1778, #1786, #1790, #1792, #1795, #1796, #1797, #1798, #1802, #1804, #1806, #1809, #1811, #1815, #1817, #1821, #1829, #1830, #1832, #1833, #1835, #1838, #1840, #1841, #1844, #1846, #1849, #1850, #1853, #1855, #1858, #1860, #1861, #1862, #1863, #1866, #1871, #1872, #1874, and #1878.
v0.9
New Features
Several improvements have been made to JVM verification:
-
For method specs that do not specify a final value for a field or array element, it is now enforced that the method must leave that field or element unmodified. This ensures soundness of the resulting override for use in compositional verification.
-
New JVM setup commands have been introduced for writing partial specifications:
jvm_modifies_field,jvm_modifies_static_field,jvm_modifies_elem, andjvm_modifies_array. Used in the post-condition section of a spec, these declare that the field or array in question may be modified by the method in an unspecified manner. -
All
jvm_functions have all been promoted from "experimental" to "current" status, so thatenable_experimentalis no longer necessary for JVM verification. -
The RPC API now includes methods for Java verification, as described here.
A new enable_lax_pointer_ordering function exists, which relaxes the restrictions that Crucible imposes on comparisons between pointers from different allocation blocks.
A SAW value of type Bool can now be brought into scope in Cryptol expressions as a value of type Bit.
A new hoist_ifs_in_goal proof tactic works like hoist_ifs but on the current goal in a proof script.
The verification summaries produced when specifying the -s flag now contain much more detailed information. When producing JSON output (-f json), the tool in the verif-viewer directory can be used to translate it to GraphViz format.
Two new experimental functions can evaluate SAWCore terms into simpler forms. The normalize_term function simplifies the given term by fully evaluating it with the SAWCore symbolic simulator but keeping it in SAWCore format. The extract_uninterp function allows certain uninterpreted functions to be replaced with extra inputs and constraints on those inputs, allowing propositional solvers to prove goals involving uninterpreted functions.
Changes
-
The linked-in version of ABC (based on the Haskell
abcBridgelibrary) has been removed. During the original planning for this removal, we marked commands based on this library as deprecated. In the end, we replaced all of them exceptcecwith Haskell implementations, so no other commands have been removed, and the following commands are now "current" again:abc(which now is the same asw4_abc_verilog)load_aigsave_aigsave_aig_as_cnfbitblastwrite_aigerwrite_cnf
We have also implemented a
w4_abc_aigercommand that writes aTermin AIGER format and invokes ABC on it as an external process. This should be very similar to the originalabccommand. Note that the pure Haskell AIGER and CNF generation code has not been heavily tuned for performance, and could likely be made more efficient. Please file issues for performance regressions you encounter!The removal of the linked-in ABC version means that the
abctactic now requires an externalabcexecutable. You can get this by downloading awith-solverspackage from the releases page, by downloading a solver package from thewhat4-solversrepository, or by building it yourself from the ABC repository. -
The LLVM bitcode reader now should support files from any LLVM version between 3.6 and 12.
-
Experimental Windows builds are again available. The
--no-coloroption may be useful if you encounter I/O trouble running the REPL.
Bug Fixes
-
Overall, closed issues #109, #120, #128, #156, #233, #316, #320, #324, #523, #561, #624, #689, #722, #727, #746, #869, #872, #900, #975, #982, #1033, #1035, #1045, #1066, #1098, #1120, #1135, #1140, #1144, #1147, #1148, #1152, #1166, #1171, #1175, #1182, #1184, #1186, #1211, #1224, #1226, #1230, #1256, #1260, #1263, #1269, #1280, #1285, #1299, #1307, #1308, #1311, #1318, #1341, #1355, #1367, #1375, #1381, #1388, #1389, #1390, #1404, #1411, #1420, #1430, and #1438.
-
Overall, merged pull requests #942, #1117, #1185, #1191, #1204, #1205, #1206, #1207, #1208, #1209, #1212, #1213, #1214, #1216, #1218, #1219, #1267, #1270, #1272, #1274, #1275, #1276, #1278, #1279, #1281, #1282, #1283, #1284, #1286, #1288, #1289, #1290, #1292, #1293, #1294, #1295, #1297, #1298, #1300, #1309, #1310, #1313, #1315, #1317, #1319, #1320, #1321, #1323, #1325, #1327, #1328, #1329, #1330, #1331, #1332, #1334, #1335, #1336, #1337, #1342, #1343, #1345, #1346, #1349, #1351, #1356, #1357, #1364, #1365, #1366, #1368, #1369, #1370, #1371, #1373, #1374, #1378, #1379, #1380, #1384, #1385, #1391, #1392, #1393, #1394, #1396, #1397, #1398, #1399, #1401, #1402, #1403, #1405, #1406, #1410, #1413, #1414, #1415, #1416, #1422, #1423, #1424, #1426, #1427, #1428, #1429, #1431, #1432, #1433, #1434, #1435, #1437, #1439, #1440, #1441, #1443, #1444, #1445, #1446, #1448, #1449, #1450, #1451, #1453, #1454, #1455, #1456, #1457, #1458, #1459, #1463, #1464, #1465, #1466, and #1468.
v0.8
New Features
SAW now includes experimental support for verifying Java code using JDK 9 or later. Verifying Java code that only uses primitive data types is known to work well, but code that imports certain classes (e.g., String) is known to suffer from issues documented here.
When verifying Java code, the path to Java can be specified with the new --java-bin-dirs/-b command-line option. Alternatively, if --java-bin-dirs is not set, then SAW searches the PATH to find Java. When the path to Java is known, SAW can automatically add system-related JAR files to the JAR path, which eliminates the need to manually specify these files with -j.
The Crucible-based interface to Java verification is now strictly an improvement over the older code base, with the addition of several features:
-
Performance of JVM verification is significantly better, as a result of removing some unnecessary instances of rewriting. This improves performance of LLVM verification, as well.
-
The new
jvm_static_field_isfunction allows describing the contents of static variables in method specifications. -
The verification code initializes all JVM classes at the start so that initializers don't run at arbitrary intermediate points and clobber static field values specified in preconditions. This means, however, that any proofs about Java code are under the assumption that all class initializers have run before the method under analysis executes.
Now that the Crucible-based verification infrastructure is sufficiently expressive and performant, we have removed all dependencies on the old jvm-verifier library.
On the LLVM side, SAWScript includes a variety of new functions for writing specification blocks:
-
The
llvm_struct_typeandllvm_packed_struct_typefunctions each construct an LLVM struct type from a list of other LLVM types. This is not to be confused with the existingllvm_structfunction, which takes a string as an argument and returns the corresponding alias type (which is often, but not necessarily, defined as a struct type). -
To avoid confusion, a new
llvm_aliasfunction now exists, andllvm_structis now a synonym forllvm_alias. Thellvm_structfunction continues to be available for now. -
The
llvm_pointer : LLVMType -> LLVMTypefunction allows construction of arbitrary LLVM pointer types. -
Two new functions,
llvm_points_to_at_typeandllvm_conditional_points_to_at_type, mirrorllvm_points_toandllvm_conditional_points_to, but cast the pointer to a different type. This may be useful when reading or writing a prefix of a larger array, for example. -
Support for using ABC as an external process is more complete:
-
SAW can now generate Verilog with multiple outputs (from
Termvalues that have tuple or vector result types, for example). -
The new commands
write_aig_externalandwrite_cnf_externalgenerate AIG and CNF files, respectively, by first writing Verilog and then using the availableabcexecutable to bit-blast to the lower-level representation. Corresponding proof tactics,offline_aig_externalandoffline_cnf_externalalso exist.
-
These changes are in preparation for removing the linked-in copy of ABC in a future release.
The saw-remote-api RPC server and associated Python client now have more complete support for LLVM verification, including:
-
More complete points-to declarations, matching what is currently available in SAWScript.
-
Support for more provers, including the full range of SBV-based and What4-based provers available in SAWScript.
-
Support for ghost variables.
-
Support for assuming LLVM contracts directly (rather than the previous behavior which would temporarily assume that failed verifications succeeded to determine whether higher-level verifications would still succeed).
-
Support for global variables and initializers.
-
Support for null pointers.
-
Support for array value literals.
-
Support for specifying the value of individual struct fields and array elements.
-
Support for specifying the alignment of allocations.
Docker images for SAW are now located on GitHub instead of DockerHub.
Changes
The proof management infrastructure in SAWScript is simpler and more consistent than before. Many of these changes are internal, to make the code less error-prone and easier to maintain in the future. Several are user-facing, though:
-
The
caseProofResultcommand now passes aTheoremargument to the first function argument, allowing its use as a rewrite rule, for example. -
A new
admittactic exists, which takes aStringargument describing why the user has decided omit proof of the goal. This replaces theassume_unsatandassume_validtactics, which we now recommend against. They will be officially deprecated in a future release, and removed after that. -
Prover tactics (e.g.,
yices) now returnProofScript ()instead ofProofScript SatResult. -
Simpsets can now contain "permutative" rewrite rules, where a rule is permutative if each side of the equality could represent the same set of terms and therefore the rule could repeatedly apply forever. A term ordering is used to prevent looping when these rules are applied.
Bug Fixes
-
Verilog generated from rotation operations is now in correct Verilog syntax.
-
Closed issues #9, #25, #39, #41, #54, #55, #69, #81, #90, #92, #124, #136, #144, #149, #152, #159, #271, #285, #323, #353, #377, #382, #431, #446, #631, #652, #739, #740, #861, #901, #908, #924, #930, #951, #962, #971, #985, #991, #993, #994, #995, #996, #1003, #1006, #1009, #1021, #1022, #1023, #1031, #1032, #1050, #1051, #1052, #1055, #1056, #1058, #1061, #1062, #1067, #1073, #1083, #1085, #1090, #1091, #1096, #1099, #1101, #1119, #1122, #1123, #1127, #1128, #1132, #1163, and #1164.
v0.7
New Features
SAW can now use the ABC prover as an external process in addition to the linked-in version. This change is in preparation for removing the linked-in version in a future release. This change has several parts:
- The new proof tactics
w4_abc_verilogandw4_abc_smtlib2allow using ABC to discharge proof goals using either Verilog or SMT-Lib2 as the intermediate file format, respectively. - The new
offline_verilogtactic writes a proof goal in the subset of Verilog supported by ABC, which can allow the use of custom ABC commands to discharge it. - The new
w4_offline_smtlib2writes a proof goal in SMT-Lib2 syntax using What4 instead of SBV. - The new
write_verilogcommand will write aTermto a file in Verilog syntax from the top level of a script. - The new
write_smtlib2_w4command will write aTermto a file in SMT-Lib2 syntax from the top level of a script, using What4 instead of SBV. - The new proof tactics
sbv_abc,sbv_boolector,sbv_cvc4,sbv_mathsat,sbv_yices,sbv_z3,sbv_unint_cvc4,sbv_unint_yices, andsbv_unint_z3are now aliases for the same tactics without thesbv_prefixes in preparation for making the unprefixed tactics refer to the What4 versions of the same functionality.
Java verification using the Crucible symbolic execution engine is now more flexible and performant.
- The new
jvm_array_iscommand specifies the entire contents of an array together. - The new
jvm_field_iscommand allows disambiguation by type for fields of the same name but different types. - JVM method names can be disambiguated using type descriptors.
- JVM constructors can be referred to by the name
<init>. - Error messages in JVM verification are significantly more helpful.
These changes, and various internal performance improvements, mean that the ECDSA verification example included with SAW now runs in around 5 minutes on a modern laptop.
New features exist to summarize any verifications performed with SAW. The summarize_verification command will print a list of all functions or methods verified or assumed, and all lemmas proved with commands such as prove. These summaries include the status (verified or assumed) of each item along with the provers used to complete the proof. The -s <filename> flag will instruct SAW to automatically write a summary to the given file, and the -f <format> flag will instruct SAW to use either a human-readable (pretty) format or JSON (json) for consumption by other tools.
An experimental RPC server for SAW now exists, which provides an alternative to SAWScript for controlling SAW execution. A client library for interacting with the server from Python exists here.
Verification of x86 code called from LLVM is now more flexible. The add_x86_preserved_reg command can add a specific register to the set that is assumed to be callee-saved, and path satisfiability checking is now performed when passing True as the fifth argument to crucible_llvm_verify_x86.
The new cryptol_add_path command adds a directory to the search path used when loading Cryptol modules (and following imports within explicitly-loaded modules).
New, shorter names are available for all LLVM commands starting with the crucible_ prefix. The new names use the llvm_ prefix instead. The top-level function crucible_llvm_verify is now llvm_verify, and crucible_llvm_unsafe_assume_spec is llvm_unsafe_assume_spec. The old names are still supported for now. The in-REPL documentation (:? <command>) gives the new name for each command.
Shorter names are available for some saw-script types: CrucibleSetup is now LLVMSetup, CrucibleMethodSpec is now simply LLVMSpec, and JVMMethodSpec is JVMSpec. The old type names are still supported for backward compatibility.
Bug Fixes
-
Catch more exceptions at the REPL (issues #138, #560, #745, and #814).
-
Ensure global memory is immutable in x86 verification.
-
Closed issues #61, #138, #158, #162, #212, #215, #265, #314, #319, #399, #412, #422, #439, #456, #544, #560, #562, #683, #686, #719, #723, #745, #814, #844, #845, #856, #866, #874, #888, #901, #902, #904, #911, #920, #936, #937, #945, and #957.