Tutorial

This tutorial shows some of the features of fm-weck and how to use them. We show how to run fm-weck via the docker container and via local installation.

Running fm-weck with Docker

We also provide a Docker image for fm-weck. This image already contains podman and fm-weck installed. It’s working directory is /app.

Pulling the Docker image from Gitlab

You can pull the fm-weck docker image from the Gitlab registry:

docker pull registry.gitlab.com/sosy-lab/software/fm-weck:latest

To make the tutorial easier to read we will tag this image with a shorter name:

docker tag registry.gitlab.com/sosy-lab/software/fm-weck:latest fm-weck

Convenience Setup (Optional)

fm-weck downloads tools and caches them. However, every time you run fm-weck via the container, the cache is lost, and the tools are downloaded again. To avoid this, you can mount a volume to the container. By default fm-weck caches tools in /root/.cache/weck_cache inside of the container. You can mount a volume to this directory to persist the cache. Mounting a volume works with the -v flag. For example, to mount the cache to /path/to/cache on your host system, you can run:

docker run -v /path/to/cache:/root/.cache/weck_cache fm-weck --help

The cache is mounted to /root/.cache/weck_cache in the container. This is where the installed fm-weck expects the cache to be. The --help command is just an example command to show that the container is working. It prints the help message of fm-weck.

We provide a convenience script to run fm-weck with the caches mounted. To use it, just source the doc/convenient_docker.sh script:

source doc/convenient_docker.sh

NOTE
This still does not cache the images used by podman. Caching these images may lead to problems on some system configurations, such as using zfs or btrfs. We recommend entering the container with an interactive shell instead.

Caching the podman images between runs

If you wish to run multiple commands that potentially share the same container image, we recommend entering the container with an interactive shell:

docker run --privileged -it --rm -v $PWD:/home --workdir /home --entrypoint /bin/bash fm-weck

This command starts an interactive shell in the container. Your current directory is mounted to /home in the container. You will start in the /home directory in the container. You can then run fm-weck commands inside the container.

Alternative: start / stop weck container

The convenient_docker.sh also comes with the start_weck_container and stop_weck_container functions. These functions start and stop the container in the background. The current directory at the time of starting the container is mounted once to the container at the moment of starting it. You will see output similar to the following:

$ start_weck_container
10f4736c43943e3b94b3ec4285838713d43bd9e360747ce89a001e9edddd7657
$ fm-weck --help
usage: fm-weck [-h] [--version] [--config CONFIG] [--loglevel LEVEL] [--logfile LOGFILE] [--list] [--dry-run]
               {run,r,expert,e,m,shell,install,i,runexec} ...

fm-weck

positional arguments:
  {run,r,expert,e,m,shell,install,i,runexec}
    run (r)             Run a verifier inside a container.
    expert (e, m)       Manually run a verifier inside a container.Arguments are passed verbatim to the
                        tool, so expert-ise about it's command line is required.
    shell               Start an interactive shell inside the container.
    install (i)         Download and unpack a TOOL for later use.
    runexec             Run runexec on a command inside a container.

options:
  -h, --help            show this help message and exit
  --version             show program's version number and exit
  --config CONFIG       Path to the configuration file.
  --loglevel LEVEL      Set the log level. Valid values are: debug, info, warning, error, critical
  --logfile LOGFILE     Path to the log file.
  --list                List all fm-tools that can be called by name.
  --dry-run             Just print the command that would be executed.
$ stop_weck_container
fm_weck

Your first fm-weck run

NOTE
From now on we will refer to fm-weck as fm-weck for brevity. If you are using the convenience script, are inside the container, or installed fm-weck via pip these commands will work as is. If you are using the docker image directly, you need to prepend --privileged to the docker commands, such that podman works inside the container.

To get an overview of the available commands run:

$ fm-weck --help
usage: fm-weck [-h] [--version] [--config CONFIG] [--loglevel LEVEL] [--logfile LOGFILE] [--list] [--dry-run]
               {run,r,expert,e,m,shell,install,i,runexec} ...

fm-weck

positional arguments:
  {run,r,expert,e,m,shell,install,i,runexec}
    run (r)             Run a verifier inside a container.
    expert (e, m)       Manually run a verifier inside a container.Arguments are passed verbatim to the
                        tool, so expert-ise about it's command line is required.
    shell               Start an interactive shell inside the container.
    install (i)         Download and unpack a TOOL for later use.
    runexec             Run runexec on a command inside a container.

options:
  -h, --help            show this help message and exit
  --version             show program's version number and exit
  --config CONFIG       Path to the configuration file.
  --loglevel LEVEL      Set the log level. Valid values are: debug, info, warning, error, critical
  --logfile LOGFILE     Path to the log file.
  --list                List all fm-tools that can be called by name.
  --dry-run             Just print the command that would be executed.

To get an overview of the available tools run:

$ fm-weck --list
List of fm-tools callable by name:
  - 2ls
  - aise
  - aprove
  - brick
  - bubaak
[!snip]
  - cpachecker
[!snip]

List of properties callable by name:
  - coverage-branches
  - coverage-conditions
  - coverage-error-call
  - coverage-statements
  - def-behavior
  - no-data-race
  - no-overflow
  - termination
  - unreach-call
  - valid-memcleanup
  - valid-memsafety

Running a tool in expert mode

fm-weck has three modes of operation: the automatic (run) mode, the manual (expert) mode and interactive (shell) mode. The expert mode allows you to run a tool and control all arguments passed to it.

Let’s look at an example: to get the version of CPAchecker, CPAchecker accepts the -version flag. To pass that flag directly to CPAchecker, you can run:

$ fm-weck m cpachecker -version
INFO:httpx:HTTP Request: GET https://zenodo.org/api/records/11074229 "HTTP/1.1 200 OK"
tool_module:  benchexec.tools.cpachecker
INFO:root:Running: ['podman', 'run', '--entrypoint', '[""]', '--cap-add', 'SYS_ADMIN', '-v', '/home/wachowitz/Projects/fm-weck/doc:/home/cwd', '-v', '/home/wachowitz/.cache/weck_cache:/home/weck_cache', '--workdir', '/home/cwd', '--rm', 'registry.gitlab.com/sosy-lab/software/cpachecker:2.3.1', PosixPath('/home/weck_cache/CPAchecker-2.3.1/scripts/cpa.sh'), PosixPath('-version')]
Running CPAchecker with default heap size (1200M). Specify a larger value with -heap if you have more RAM.
Running CPAchecker with default stack size (1024k). Specify a larger value with -stack if needed.

CPAchecker 2.3.1 (OpenJDK 64-Bit Server VM 17.0.11)

You see some INFO output from fm-weck followed by the output of CPAchecker.

We can also run CPAchecker as “experts”, i.e., someone who knows how set CPAcheckers commandline.

NOTE
Depending on your system podman might print an error message similar to

WARN[0020] Failed to add conmon to cgroupfs sandbox cgroup: creating cgroup path /libpod_parent/conmon: write /sys/fs/cgroup/cgroup.subtree_control: device or resource busy

This does not affect the execution of fm-weck. You may ignore this message.

Assuming you are in the doc directory of the fm-weck repository, you can run:

$ fm-weck m cpachecker --default examples/example-safe.c
INFO:httpx:HTTP Request: GET https://zenodo.org/api/records/11074229 "HTTP/1.1 200 OK"
tool_module:  benchexec.tools.cpachecker
INFO:root:Running: ['podman', 'run', '--entrypoint', '[""]', '--cap-add', 'SYS_ADMIN', '-v', '/home/wachowitz/Projects/fm-weck/doc:/home/cwd', '-v', '/home/wachowitz/.cache/weck_cache:/home/weck_cache', '--workdir', '/home/cwd', '--rm', 'registry.gitlab.com/sosy-lab/software/cpachecker:2.3.1', PosixPath('/home/weck_cache/CPAchecker-2.3.1/scripts/cpa.sh'), '-default', 'examples/example-safe.c']
Running CPAchecker with default heap size (1200M). Specify a larger value with -heap if you have more RAM.
Running CPAchecker with default stack size (1024k). Specify a larger value with -stack if needed.
JVM property file.encoding is set to non-standard value 'ANSI_X3.4-1968'. This is not recommended and output files might be written in unexpected encodings. (CPAMain.main, WARNING)
Language C detected and set for analysis (CPAMain.detectFrontendLanguageIfNecessary, INFO)

[!snip]

Stopping analysis ... (CPAchecker.runAlgorithm, INFO)

Verification result: TRUE. No property violation found by chosen configuration.
More details about the verification run can be found in the directory "./output".
Graphical representation included in the file "./output/Report.html".

$ ls output
abstractions.txt  ARGSimplified.dot  cfa      cfaPixel.svg   CPALog.txt      functionCalls.dot      Report.html     UsedConfiguration.properties  VariableTypeMapping.txt
ARG.dot           ARG.svg            cfa.dot  coverage.info  CPALog.txt.lck  functionCallsUsed.dot  Statistics.txt  VariableClassification.log    witness-2.0.yml

CPAchecker produced the verification result TRUE, meaning it could prove the property (here: the default that was set by the CPAchecker developers) valid.

Let’s clean up the output directory:

rm -r output

Running a tool in automatic mode

NOTE
All commands in this section assume that you are in the /app directory of the container or the /doc directory of the fm-weck repository if running locally.

The automatic mode allows you to run a tool without knowing all the command line arguments. You can specify the tool by name:version and the property by name.

Let us again run CPAchecker on the example-safe.c file. This time we know that we want to check for a the unreach-call property. The unreach-call property instructs the verifier to check if a special function, called reach_error(), is reachable in the supplied program file.

To get rid of leftover files from the previous run, clean up the output directory:

$ rm -r output
$ fm-weck run cpachecker:2.3.1 --property unreach-call examples/example-safe.c
INFO:httpx:HTTP Request: GET https://zenodo.org/api/records/11074229 "HTTP/1.1 200 OK"
tool_module:  benchexec.tools.cpachecker
INFO:fm_weck.engine:Running: ['podman', 'run', '--entrypoint', '[""]', '--cap-add', 'SYS_ADMIN', '-v', '/app:/home/cwd', '-v', '/root/.cache/weck_cache:/home/weck_cache', '-v', '/tmp/tmp1soytyaofm_weck_output:/home/output', '--workdir', '/home/cwd', '--rm', 'registry.gitlab.com/sosy-lab/software/cpachecker:2.3.1', '/home/weck_cache/.scripts/run_with_overlay.sh', 'CPAchecker-2.3.1', './scripts/cpa.sh', '-svcomp24', '-heap', '10000M', '-benchmark', '-timelimit', '900 s', '-stats', '-spec', PosixPath('/home/weck_cache/.properties/unreach-call.prp'), '-64', 'examples/example-safe.c']
Running CPAchecker with Java heap of size 10000M.
Running CPAchecker with default stack size (1024k). Specify a larger value with -stack if needed.
Language C detected and set for analysis (CPAMain.detectFrontendLanguageIfNecessary, INFO)

Using the following resource limits: CPU-time limit of 900s (ResourceLimitChecker.fromConfiguration, INFO)

CPAchecker 2.3.1 / svcomp24 (OpenJDK 64-Bit Server VM 17.0.11) started (CPAchecker.run, INFO)

[!snip]

Time for Garbage Collector:       0.016s (in 4 runs)
Garbage Collector(s) used:    G1 Old Generation, G1 Young Generation

Verification result: TRUE. No property violation found by chosen configuration.
More details about the verification run can be found in the directory "./output".

CPAchecker again produced the verification result TRUE, meaning it could prove the property. If we take a look at the output directory, we see that it now contains the output of the automatic run:

$ ls output
witness.graphml  witness.yml

A closer inspection of the automatic run

NOTE
This section does a little detour into the inner workings of fm-weck. If you just want to use fm-weck, or test the artifact, this section can be skipped.

Comparing how CPAchecker was called in the expert mode vs. the automatic mode, we see that in the automatic mode there are more arguments passed to CPAchecker. This is because the automatic mode adds the arguments recommended by the tool developers to the command line.

Peeking at the cpachecker.yml configuration file, we see that version 2.3.1 of CPAchecker recommends the arguments -svcomp24, -heap 10000M, -benchmark, and -timelimit 900 s.

versions:
  - version: "2.3.1"
    doi: 10.5281/zenodo.11074229
    benchexec_toolinfo_options: ["-svcomp24", "-heap", "10000M", "-benchmark", "-timelimit", "900 s"]
    required_ubuntu_packages:
      - openjdk-17-jdk-headless
    base_container_images:
      - docker.io/ubuntu:22.04
    full_container_images:
      - registry.gitlab.com/sosy-lab/software/cpachecker:2.3.1

This is reflected in the command line arguments passed to CPAchecker in the automatic mode:

# expert mode
INFO:root:Running: [ !snip ..., '/home/weck_cache/CPAchecker-2.3.1/scripts/cpa.sh', '-default', 'examples/example-safe.c']
# automatic mode
INFO:root:Running: [ !snip ..., './scripts/cpa.sh', '-svcomp24', '-heap', '10000M', '-benchmark', '-timelimit', '900 s', '-stats', '-spec', PosixPath('/home/weck_cache/.properties/unreach-call.prp'), '-64', 'examples/example-safe.c']

We can see another difference in the output of the two runs:

  • the expert run just calls the executable of the tool, in this case cpa.sh, with an absolute path to the the executable.

  • while the automatic run calls the executable relative to the root of the tool directory (/home/weck_cache/CPAchecker-2.3.1), in this case ./scripts/cpa.sh.

In fact the automatic mode uses a script run_with_overlay.sh to overlay the tool directory over the current working directory inside the container. This allows fm-weck to also run the many tools that rely on being called from their root directory. One of those – UAutomizer – will be executed in the next section.

Running a different tool

So far we have only run CPAchecker. We now demonstrate, that it is super simple to run other tools from the fm-tools repository.

  1. We run UAutomizer on the example-safe.c file:

If you want to compare the output of your run with the expected output further down, you can run:

$ rm -r output
$ fm-weck run uautomizer:svcomp24 --property unreach-call examples/example-safe.c
INFO:httpx:HTTP Request: GET https://zenodo.org/api/records/10203545 "HTTP/1.1 200 OK"
INFO:httpx:HTTP Request: GET https://zenodo.org/api/records/10203545/files/uautomizer.zip/content "HTTP/1.1 200 OK"
129860KiB [00:04, 31412.89KiB/s]                                                                                                                                              
INFO:httpx:HTTP Request: GET https://zenodo.org/api/records/10203545 "HTTP/1.1 200 OK"
tool_module:  benchexec.tools.ultimateautomizer
INFO:root:Running: ['podman', 'run', '--entrypoint', '[""]', '--cap-add', 'SYS_ADMIN', '-v', '/home/wachowitz/Projects/fm-weck/doc:/home/cwd', '-v', '/home/wachowitz/.cache/weck_cache:/home/weck_cache', '--workdir', '/home/cwd', '--rm', 'registry.gitlab.com/sosy-lab/benchmarking/competition-scripts/user:2024', '/home/weck_cache/.scripts/run_with_overlay.sh', 'UAutomizer-svcomp24', './Ultimate.py', '--spec', PosixPath('/home/weck_cache/.properties/unreach-call.prp'), '--file', 'examples/example-safe.c', '--full-output', '--architecture', '64bit']
Checking for ERROR reachability
Using default analysis
Version 0e0057cc
Calling Ultimate with: /usr/lib/jvm/java-1.11.0-openjdk-amd64/bin/java -Dosgi.configuration.area=/home/_cwd/data/config -Xmx15G -Xms4m -jar /home/_cwd/plugins/org.eclipse.equinox.launcher_1.5.800.v20200727-1323.jar -data @noDefault -ultimatedata /home/_cwd/data -tc /home/_cwd/config/AutomizerReach.xml -i examples/example-safe.c -s /home/_cwd/config/svcomp-Reach-64bit-Automizer_Default.epf --cacsl2boogietranslator.entry.function main --witnessprinter.witness.directory /home/_cwd --witnessprinter.witness.filename witness --witnessprinter.write.witness.besides.input.file false --witnessprinter.graph.data.specification CHECK( init(main()), LTL(G ! call(reach_error())) )

 --witnessprinter.graph.data.producer Automizer --witnessprinter.graph.data.architecture 64bit --witnessprinter.graph.data.programhash 63b4a5254a86dd212025f3e9aec65d99d090a4eb0087d6a42e6ba5c8a1987f15
--- Real Ultimate output ---
This is Ultimate 0.2.4-dev-0e0057c
[!snip]
--- End real Ultimate output ---

Execution finished normally
Writing output log to file Ultimate.log
Result:
TRUE

UAutomizer also produced the verification result TRUE, meaning it could prove the property. Additionally, the output directory contains the witness:

$ ls output
data  Ultimate.log  witness.graphml  witness.yml
  1. We run UAutomizer on the AdditionIntMax.i file to check for the no-overflow property:

$ fm-weck run uautomizer:svcomp24 --property no-overflow examples/AdditionIntMax.i
INFO:httpx:HTTP Request: GET https://zenodo.org/api/records/10203545 "HTTP/1.1 200 OK"
tool_module:  benchexec.tools.ultimateautomizer
INFO:root:Running: ['podman', 'run', '--entrypoint', '[""]', '--cap-add', 'SYS_ADMIN', '-v', '/home/wachowitz/Projects/fm-weck/doc:/home/cwd', '-v', '/home/wachowitz/.cache/weck_cache:/home/weck_cache', '--workdir', '/home/cwd', '--rm', 'registry.gitlab.com/sosy-lab/benchmarking/competition-scripts/user:2024', '/home/weck_cache/.scripts/run_with_overlay.sh', 'UAutomizer-svcomp24', './Ultimate.py', '--spec', PosixPath('/home/weck_cache/.properties/no-overflow.prp'), '--file', 'examples/AdditionIntMax.i', '--full-output', '--architecture', '64bit']
Checking for overflows
Using default analysis
Version 0e0057cc
Calling Ultimate with: /usr/lib/jvm/java-1.11.0-openjdk-amd64/bin/java -Dosgi.configuration.area=/home/_cwd/data/config -Xmx15G -Xms4m -jar /home/_cwd/plugins/org.eclipse.equinox.launcher_1.5.800.v20200727-1323.jar -data @noDefault -ultimatedata /home/_cwd/data -tc /home/_cwd/config/AutomizerReach.xml -i examples/AdditionIntMax.i -s /home/_cwd/config/svcomp-Overflow-64bit-Automizer_Default.epf --cacsl2boogietranslator.entry.function main --witnessprinter.witness.directory /home/_cwd --witnessprinter.witness.filename witness --witnessprinter.write.witness.besides.input.file false --witnessprinter.graph.data.specification CHECK( init(main()), LTL(G ! overflow) )

 --witnessprinter.graph.data.producer Automizer --witnessprinter.graph.data.architecture 64bit --witnessprinter.graph.data.programhash 17515b65d583c44dcb7e235e0e9227ff5f3e328b2b111df737a68b768cd4ce6e
--- Real Ultimate output ---
This is Ultimate 0.2.4-dev-0e0057c
[!snip]
--- End real Ultimate output ---

Execution finished normally
Writing output log to file Ultimate.log
Writing human readable error path to file UltimateCounterExample.errorpath
Result:
FALSE(OVERFLOW)

UAutomizer produced the verification result FALSE(OVERFLOW), meaning it could not prove the property and there is and integer overflow in the program. The output directory contains the counter example:

$ ls output
data  UltimateCounterExample.errorpath  Ultimate.log  witness.graphml  witness.yml

Working with local configuration

We have seen automatic and expert runs of fm-weck with two analyzers that have all necessary information available in fm-data, CPAchecker and UAutomizer. It is also possible to execute analyzers that have an SV-COMP archive, but miss the fm-data information. We show this on the example of the static analysis tool Goblint. Goblint is a static analysis tool that can be used to check for integer overflows.

  1. We run goblint on the AdditionIntMax.i file to check for the no-overflow property:

$ fm-weck run goblint:svcomp24 --property no-overflow examples/AdditionIntMax.i
INFO:httpx:HTTP Request: GET https://zenodo.org/api/records/10202867 "HTTP/1.1 200 OK"
INFO:httpx:HTTP Request: GET https://zenodo.org/api/records/10202867/files/goblint.zip/content "HTTP/1.1 200 OK"
22908KiB [00:11, 1927.71KiB/s]
INFO:httpx:HTTP Request: GET https://zenodo.org/api/records/10202867 "HTTP/1.1 200 OK"
INFO:httpx:HTTP Request: GET https://gitlab.com/sosy-lab/software/benchexec/-/raw/main/benchexec/tools/goblint.py "HTTP/1.1 200 OK"
ERROR:fm_weck.cli:
No image specified in the fm-tool yml file for goblint.
There is currently no configuration file found in the search path.
The search order was
.fm-weck
/home/<your home>/.fm-weck
/home/<your home>/.config/fm-weck
/home/<your home>/.config/fm-weck/config.toml
Please specify an image in the fm-tool yml file or add a configuration.

To add a configuration you can do the following (on POSIX Terminals):

printf '[defaults]\nimage = "<your_image>"' > .fm-weck

Replace <your_image> with the image you want to use.

OH NO! there is not yet an image specified for Goblint in the fm-tools repository. The error message also tells us how to fix this: we can specify an image in a configuration file.

Let’ create a configuration file for fm-weck. Goblint took part in SV-COMP 2024, so we can assume, that it runs in the SV-COMP 2024 environment. The SV-COMP 2024 image is registry.gitlab.com/sosy-lab/benchmarking/competition-scripts/user:2024.

$ printf '[defaults]\nimage = "registry.gitlab.com/sosy-lab/benchmarking/competition-scripts/user:2024"' > .fm-weck

Now we can rerun the command:

$ fm-weck run goblint:svcomp24 --property no-overflow examples/AdditionIntMax.i
tool_module:  .goblint
[!snip]
SV-COMP result: unknown
[Info][Witness] witness generation summary:
  total generation entries: 1

Goblint produced the verification result unknown, meaning it could not prove the property. The automatic mode uses the svcomp24 configuration for Goblint, which will not produce errors and instead returns unknown whenever it cannot prove the property.

Running an interactive shell

To enter an interactive shell inside the container, you can run:

$ fm-weck shell cpachecker:2.3.1
root@62e2a8fcca5a:/home/cwd# ls
convenient_docker.sh  examples  output  README-Artifact.md  shell-completion-setup.md  Tutorial.md
root@62e2a8fcca5a:/home/cwd# exit
exit

This will start an interactive shell inside the container with the CPAchecker image. The current directory is mounted to /home/cwd in the container, which is also the working directory.

NOTE The next step will only work if you have completed Example 3 of ‘Runing a different tool’ (Goblint) and have created a configuration file.

You can also start an interactive shell just from the configuration file:

$ fm-weck shell
root@ba9a6acc5552:/home/cwd# 

This will start an interactive shell inside the container with the image specified in the configuration file.

Installing tools for later use

fm-weck can download and cache tools for later use. If you want to install goblint, cpachecker and cbmc for later use, you can run:

$ fm-weck install goblint cpachecker cbmc