ByteBack is a deductive verifier for Java that works at the level of JVM bytecode. It provides an annotation library to specify programs at the source code level in a way that "survives" compilation to bytecode. Then, ByteBack encodes bytecode programs into Boogie, which performs the actual verification.
By working on bytecode while supporting specification at the source code level, ByteBack can accommodate a lot of Java features in a uniform way. In fact, it can verify programs written in recent Java versions, and even supports some features of other JVM languages such as Kotlin and Scala.
The simplest way of using ByteBack is through its Docker image. The
image is available on DockerHub (<paganma/byteback:latest
>), and can
be built using the provided Dockerfile.
Build ByteBack using Gradle:
./gradlew install
This command builds:
- The command line executable
byteback-cli
in ./byteback-cli/build/install/byteback-cli/bin/byteback-cli. - The
.jar
archive withbyteback-cli
's implementation in ./byteback-cli/build/libs/byteback-cli.jar. - The
byteback-annotations
library (BBLib) in ./byteback-annotations/build/libs/byteback-annotations.jar.
As mentioned above, ByteBack encodes bytecode programs into Boogie. To verify ByteBack's Boogie output, you also need to install:
For example, Z3 can be installed through pypi
using the
./requirements.txt
file, while Boogie can be installed by using the
.NET SDK 6:
dotnet tool install -g boogie
ByteBack includes system tests and verification experiments. A separate file describes how to run them.
Let's see how to use byteback-cli
to verify the Java program
Main.java
in ./example.
Main.java
contains a single method positive_sum
with pre- and
postcondition:
@Predicate
public boolean positive_arguments(int a, int b) {
return gte(a, 0) & gte(b, 0);
}
@Predicate
public boolean positive_return(int a, int b, int returns) {
return gte(returns, 0);
}
@Require("positive_arguments") // a >= 0 && b >= 0
@Ensure("positive_return") // returns >= 0
public int positive_sum(int a, int b) {
return a + b;
}
To verify this simple program, go to directory ./example and follow these steps:
- Compile
Main.java
, including theBBlib
.jar
in the classpath:
javac Main.java -cp ../byteback-annotations/build/libs/byteback-annotations.jar
This generates bytecode for class Main
.
- Run ByteBack using
byteback-cli
on the generated bytecode:
# The PATH to byteback-cli is already set in the Docker image
export PATH="$PATH:../byteback-cli/build/install/byteback-cli/bin/"
byteback-cli \
-cp ../byteback-annotations/build/libs/byteback-annotations.jar \
-cp . \
-c Main \
-o Main.bpl
This generates a Boogie program Main.bpl
, which encodes the Java
program's semantics and its specification in Boogie.
- Finally, verify the generated Boogie program using the Boogie verifier:
boogie Main.bpl
This should return with a successful verification:
Boogie program verifier finished with 2 verified, 0 errors
byteback-cli
is the command line tool that runs ByteBack. It inputs
Java bytecode and outputs Boogie programs. byteback-cli
supports the
following options:
byteback-cli \
-cp CLASS_PATH \
-c TARGET_CLASS \
[ -o BOOGIE_OUTPUT ] \
[ -p PRELUDE ]\
[ --npe ] \
[ --iobe ]
-
-cp CLASS_PATH
declares the classpath where ByteBack will look for bytecode to be analyzed. You can repeat this option to specify multiple classpaths. -
-c TARGET_CLASS
give the fully qualified name of an entry class for ByteBack's analysis. You can repeat this option to declare multiple entry classes. ByteBack will recursively process all application classes that are referenced from any entry class (excluding standard library classes). -
-o BOOGIE_OUTPUT
declares the name of the output Boogie file generated by ByteBack. If this option is omitted, ByteBack prints the Boogie program to standard output. -
-p PRELUDE
specifies the Boogie prelude files to be used. If this option is omitted, ByteBack uses its standard prelude. -
--npe
enables support for verifying behavior of implicitNullPointer
exceptions. -
--iobe
enables support for verifying behavior of implicitIndexOutOfBounds
exceptions.
BBLib, the ByteBack annotations library, includes annotations and static methods for specifying functional properties at the level of Java source code, or any other language that compiles to JVM bytecode.
See the annotated programs in ./byteback-test for examples of using BBLib.
To cite ByteBack refer to the paper:
Marco Paganoni and Carlo A. Furia. Verifying Functional Correctness Properties At the Level of Java Bytecode. In Proceedings of the 25th International Symposium on Formal Methods (FM). Lecture Notes in Computer Science, 14000:343–363, Springer, March 2023.
@InProceedings{PF-FM23-ByteBack,
author = {Marco Paganoni and Carlo A. Furia},
title = {Verifying Functional Correctness Properties At the Level of {J}ava Bytecode},
booktitle = {Proceedings of the 25th International Symposium on Formal Methods (FM)},
year = {2023},
series = {Lecture Notes in Computer Science},
pages = {343--363},
volume = {14000},
publisher = {Springer}
}
Another publication describing the research behind ByteBack:
Marco Paganoni and Carlo A. Furia. Reasoning About Exceptional Behavior At the Level of Java Bytecode. In Proceedings of the 18th International Conference on integrated Formal Methods (iFM). Lecture Notes in Computer Science, 14300:113–133, Springer, November 2023.
@InProceedings{PF-iFM23-ByteBack,
author = {Marco Paganoni and Carlo A. Furia},
title = {Reasoning About Exceptional Behavior At the Level of {J}ava Bytecode},
booktitle = {Proceedings of the 18th International Conference on integrated Formal Methods (iFM)},
year = {2023},
series = {Lecture Notes in Computer Science},
pages = {113--133},
volume = {14300},
publisher = {Springer},
}