Skip to content

Commit 6953507

Browse files
author
Joel Allred
authored
Merge pull request #3404 from diffblue/allredj/doc-jbmc-user-manual
Add JBMC user manual [DOC-9]
2 parents 8aa31fe + 00ac7b8 commit 6953507

File tree

1 file changed

+268
-0
lines changed

1 file changed

+268
-0
lines changed
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
\ingroup module_hidden
2+
\page jbmc-user-manual JBMC User Manual
3+
4+
5+
\section jbmc-manual-intro Introduction
6+
7+
JBMC is a bounded model checking tool for the Java language. It follows the
8+
same principles as CBMC, thus the existing
9+
[documentation for CBMC](http://www.cprover.org/cprover-manual/cbmc.html)
10+
largely applies to JBMC.
11+
12+
In brief, JBMC creates a model from Java Bytecode (given as input as a .class
13+
file or a .jar) and performs static analysis and symbolic execution which allow
14+
us to prove or refute properties. These properties are either automatically
15+
generated (runtime errors), or provided by the user in the form of assertions.
16+
17+
Using examples, the following section will guide you through the basic
18+
features of JBMC.
19+
20+
21+
\section jbmc-tutorial JBMC tutorial
22+
23+
\subsection jbmc-manual-auto-assert Automatic assertions
24+
25+
Consider the following simplistic `ExampleArray.java` file which we have
26+
compiled into `tutorial/ExampleArray.class` and which queries the array of
27+
input arguments at index 3:
28+
```
29+
1| package tutorial;
30+
2|
31+
3| public class ExampleArray {
32+
4|
33+
5| public static void main(String[] args) {
34+
6| final int index = 3;
35+
7| String arg3 = args[index];
36+
8| }
37+
9|
38+
10| }
39+
```
40+
41+
Now let's run the following command to let JBMC tell us about potential errors
42+
in our program.
43+
44+
$ jbmc tutorial/ExampleArray.class
45+
46+
The output contains the following:
47+
```c
48+
[java::tutorial.ExampleArray.main:([Ljava/lang/String;)V.null-pointer-exception.1] line 7 Null pointer check: SUCCESS
49+
[java::tutorial.ExampleArray.main:([Ljava/lang/String;)V.array-index-out-of-bounds-low.1] line 7 Array index should be >= 0: SUCCESS
50+
[java::tutorial.ExampleArray.main:([Ljava/lang/String;)V.array-index-out-of-bounds-high.1] line 7 Array index should be < length: FAILURE
51+
[java::tutorial.ExampleArray.main:([Ljava/lang/String;)V.1] line 7 no uncaught exception: SUCCESS
52+
53+
** 1 of 13 failed (2 iterations)
54+
VERIFICATION FAILED
55+
```
56+
57+
We have a reported failure: JBMC found that the array access could potentially
58+
be out of bounds, if the size of the argument array is too small.
59+
60+
If we make our code more robust by adding guards to make the array access
61+
safe as follows:
62+
```
63+
1| package tutorial;
64+
2|
65+
3| public class ExampleArraySafe {
66+
4|
67+
5| public static void main(String[] args) {
68+
6| final int index = 3;
69+
7| String arg3 = "none";
70+
8| if (index < args.length) {
71+
9| arg3 = args[index];
72+
10| }
73+
11| }
74+
12|
75+
13| }
76+
```
77+
then when running JBMC on that corrected version:
78+
79+
$ jbmc tutorial/ExampleArraySafe.class
80+
81+
all the automatic assertions become valid, meaning that there is no
82+
possible inputs (argument values) for which they can be violated:
83+
```c
84+
[java::tutorial.ExampleArraySafe.main:([Ljava/lang/String;)V.1] line 7 no uncaught exception: SUCCESS
85+
[java::tutorial.ExampleArraySafe.main:([Ljava/lang/String;)V.null-pointer-exception.1] line 8 Null pointer check: SUCCESS
86+
[java::tutorial.ExampleArraySafe.main:([Ljava/lang/String;)V.null-pointer-exception.2] line 9 Null pointer check: SUCCESS
87+
[java::tutorial.ExampleArraySafe.main:([Ljava/lang/String;)V.array-index-out-of-bounds-low.1] line 9 Array index should be >= 0: SUCCESS
88+
[java::tutorial.ExampleArraySafe.main:([Ljava/lang/String;)V.array-index-out-of-bounds-high.1] line 9 Array index should be < length: SUCCESS
89+
```
90+
91+
\subsection jbmc-manual-unwind Loop unwinding
92+
93+
As CBMC, JBMC needs to unwind loops up to a given value. Consider the `isPrime`
94+
method in the code below. Without specifying an unwind limit, JBMC will not
95+
terminate when analyzing the following function whose state representation is
96+
theoretically unbounded (because of the for-loop whose number of iterations
97+
depends on an input):
98+
```
99+
1| package tutorial;
100+
2|
101+
3| public class ExampleUnwind {
102+
4|
103+
5| public static void doSomething(int inputVal) {
104+
6| if (inputVal > 1 && inputVal % 2 == 1) {
105+
7| assert isPrime(inputVal);
106+
8| // do something
107+
9| }
108+
10| }
109+
11|
110+
12| public static boolean isPrime(int candidate) {
111+
13| for (int div = 2; div * div <= candidate; div++) {
112+
14| if (candidate % div == 0) {
113+
15| return false;
114+
16| }
115+
17| }
116+
18| return candidate > 1;
117+
19| }
118+
20|
119+
21| }
120+
```
121+
To limit the number of times the for-loop is unwound, we use the `--unwind N`
122+
options, in which case the following call to JBMC:
123+
124+
$ jbmc tutorial/ExampleUnwind.class --function tutorial.ExampleUnwind.isPrime --unwind 10
125+
126+
will terminate correctly. In this case, we will see `VERIFICATION SUCCESSFUL`,
127+
as no automatic assertions are violated.
128+
129+
Note that in that example, there are is no main function, so we give specify
130+
the desired entry point via the `--function` option.
131+
132+
133+
\subsection jbmc-manual-user-assert User assertions
134+
135+
Elaborating on the example above, users may provide their own assertions, that
136+
JBMC will try to refute. On line 7, we check the assertion that all odd
137+
numbers greater than 1 are prime. To be sure that this always holds, we run
138+
JBMC on the example, with a reasonable `unwind` value:
139+
140+
$ jbmc tutorial/ExampleUnwind.class --function tutorial.ExampleUnwind.doSomething --unwind 10
141+
142+
Unsurprisingly JBMC doesn't agree, and prints an assertion failure
143+
(truncated here for readability):
144+
```c
145+
[...doSomething:(I)V.assertion.1] line 7 assertion at file tutorial/ExampleUnwind.java: FAILURE
146+
```
147+
148+
Rerunning the analysis with the `--trace` option, the following line appears
149+
somewhere in the trace output and tells us which input value JBMC found to
150+
trigger the violation (note that to see the original parameter names in the
151+
trace output, the Java source must be compiled in debug mode: `javac -g`):
152+
```c
153+
INPUT inputVal: 15
154+
```
155+
The value chosen by JBMC is arbitrary, and could as well be 9
156+
or 2084569161.
157+
158+
\subsection jbmc-manual-library Java Library support
159+
160+
The examples above only involve primitive types. In order to analyse code
161+
involving Java Library classes, the core models (located in the same
162+
repository) need to be added to the classpath:
163+
164+
--cp <path_to_cbmc>/jbmc/src/java_bytecode/library/core-models.jar
165+
166+
167+
The core models library simulate the behavior of the Java Library and
168+
contains some commonly used classes, such as Object, Class, String, Enum.
169+
Some JBMC-specific utilities reside in the `org.cprover` package.
170+
171+
Using the models, JBMC can reason with a variety of String operations
172+
from `java.lang.String`, e.g.
173+
```
174+
1| package tutorial;
175+
2|
176+
3| public class ExampleModels {
177+
4|
178+
5| public static void main(String[] args) {
179+
6| StringBuilder sb = new StringBuilder("abcd");
180+
7| StringBuilder sb2 = sb.insert(2, "$");
181+
8| assert sb2.toString().startsWith("abc");
182+
9| }
183+
10|
184+
11| }
185+
```
186+
The following command line (note that the current directory is also added to
187+
the classpath):
188+
189+
$ jbmc tutorial/ExampleModels.class --cp <path_to_cbmc>/jbmc/src/java_bytecode/library/core-models.jar:.
190+
191+
will flag this violation (truncated):
192+
```c
193+
[java::tutorial.ExampleModels.stringOp:()V.assertion.1] line 8 assertion: FAILURE
194+
```
195+
196+
Again, the trace (when re-running with `--trace`) shows the string violating
197+
the condition in the assertion:
198+
```c
199+
dynamic_object2={ 'a', 'b', '$', 'c', 'd' }
200+
```
201+
202+
\subsection jbmc-manual-exceptions Exceptions
203+
204+
In its analysis, JBMC can take into account exceptions thrown by user code or
205+
library classes, as well as runtime exceptions such as NullPointerException.
206+
To have JBMC reliably notify about all uncaught exceptions, the
207+
`--throw-runtime-exceptions` can be used.
208+
209+
Consider the following code:
210+
```
211+
1| package tutorial;
212+
2|
213+
3| public class ExampleExceptions {
214+
4|
215+
5| public static int strLength(String str) {
216+
6| return str.length();
217+
7| }
218+
8|
219+
9| }
220+
```
221+
222+
When given the `--throw-runtime-exceptions` options:
223+
224+
$ jbmc tutorial/ExampleExceptions --tutorial.ExampleExceptions.strLength --throw-runtime-exceptions
225+
226+
JBMC will signal that the `str.length()` call may throw a runtime exception
227+
and that this exception is not caught.
228+
229+
```c
230+
[java::tutorial.ExampleExceptions.strLength:(Ljava/lang/String;)I.1] line 6 no uncaught exception: FAILURE
231+
```
232+
This could be fixed by adding a try-catch statement, or else checking that
233+
`str` is non-null before accessing it.
234+
235+
To silence errors about uncaught exceptions while keeping JBMC's ability to
236+
throw runtime exceptions (for example when analyzing code that has try-catch
237+
blocks), the `--disable-uncaught-exception-check` option can be added.
238+
In our example, the assertion check will disappear completely
239+
from the output:
240+
```
241+
Generated 2 VCC(s), 0 remaining after simplification
242+
VERIFICATION SUCCESSFUL
243+
```
244+
245+
When analyzing this function without runtime exception support:
246+
247+
$ jbmc tutorial/ExampleExceptions
248+
249+
JBMC only reports the error as a null pointer check failure:
250+
```
251+
[...null-pointer-exception.1] line 6 Null pointer check: FAILURE
252+
[...strLength:(Ljava/lang/String;)I.1] line 6 no uncaught exception: SUCCESS
253+
```
254+
255+
It is worth noting that in the JVM, `assert` actually throws an AssertionError
256+
on violation. This behavior can be replicated in JBMC by using the
257+
`--throw-assertion-error`. Violations of user assertions (if uncaught) would
258+
then be reported like any other uncaught exception.
259+
260+
261+
\subsection jbmc-manual-further-doc Further documentation
262+
263+
JBMC has a wealth of other options that can either constrain the model (to
264+
cope with complexity issues), or output more relevant information. The list
265+
of all available options is printed by running:
266+
267+
$ jbmc --help
268+

0 commit comments

Comments
 (0)