Skip to content

Commit a58697f

Browse files
author
Joel Allred
committed
Add JBMC user manual
1 parent db386ea commit a58697f

File tree

1 file changed

+229
-0
lines changed

1 file changed

+229
-0
lines changed
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
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 .class
13+
files) and performs static analysis and symbolic simulation which allow to
14+
prove or refute properties. These properties are either automatically
15+
generated, 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, and explore the most useful features.
19+
20+
21+
\section jbmc-tutorial JBMC tutorial
22+
23+
\subsection jbmc-manual-auto-assert Automatic assertions
24+
25+
Consider the following simplistic `Example.java` file which we have compiled
26+
into `Example.class` and which contains a utility method to query a given
27+
array at a given index:
28+
```java
29+
1 package core;
30+
2
31+
3 public class Example {
32+
4
33+
5 public static int query(int[] array, int index) {
34+
6 return array[index];
35+
7 }
36+
8 }
37+
```
38+
39+
Now let's run the following command to let JBMC tell us about potential errors
40+
in our `query` method.
41+
```
42+
jbmc Example.class --function core.Example.query
43+
```
44+
45+
The output contains the following:
46+
```
47+
core/Example.java function java::core.Example.query:([II)I
48+
[java::core.Example.query:([II)I.null-pointer-exception.1] line 6 Null pointer check: FAILURE
49+
[java::core.Example.query:([II)I.array-index-out-of-bounds-low.1] line 6 Array index should be >= 0: FAILURE
50+
[java::core.Example.query:([II)I.array-index-out-of-bounds-high.1] line 6 Array index should be < length: FAILURE
51+
[java::core.Example.query:([II)I.1] line 6 no uncaught exception: SUCCESS
52+
```
53+
Three reported failures spring up:
54+
1) there is no null pointer check on the array passed as argument
55+
2) there is no check that the index at which we access the array is non-negative
56+
3) there is no check that the index is within the length of the array.
57+
58+
If we make our code more robust by adding guards to make the array access
59+
safe as follows:
60+
```java
61+
5 public static int query(int[] array, int index) {
62+
6 if (array == null) {
63+
7 return -1;
64+
8 }
65+
9 if (index < 0 || index >= array.length) {
66+
10 return -1;
67+
11 }
68+
12 return array[index];
69+
13 }
70+
```
71+
72+
then the JBMC automatic assertions become valid, meaning that there is no
73+
possible inputs (argument values) for which they can be violated:
74+
```
75+
core/Example.java function java::core.Example.query:([II)I
76+
[java::core.Example.query:([II)I.1] line 6 no uncaught exception: SUCCESS
77+
[java::core.Example.query:([II)I.null-pointer-exception.1] line 9 Null pointer check: SUCCESS
78+
[java::core.Example.query:([II)I.null-pointer-exception.2] line 12 Null pointer check: SUCCESS
79+
[java::core.Example.query:([II)I.array-index-out-of-bounds-low.1] line 12 Array index should be >= 0: SUCCESS
80+
[java::core.Example.query:([II)I.array-index-out-of-bounds-high.1] line 12 Array index should be < length: SUCCESS
81+
```
82+
83+
\subsection jbmc-manual-unwind Loop unwinding
84+
85+
As in CBMC, JBMC transforms the input program into a state representation,
86+
and thus needs to unwind loops up to a given value. Without specifying a
87+
unwind limit, JBMC will not terminate when analysing the following function
88+
whose state representation is theoretically unbounded (because of the for-loop
89+
whose number of iterations depends on an input):
90+
```java
91+
public static boolean isPrime(int candidate) {
92+
for (int div = 2; div <= candidate / 2; div++) {
93+
if (candidate % div == 0) {
94+
return false;
95+
}
96+
}
97+
return candidate > 1;
98+
}
99+
```
100+
To limit the number of times the for-loop is unwound, we use the `--unwind N`
101+
options, in which case the following call to JBMC:
102+
```
103+
jbmc Example.class --function core.Example.isPrime --unwind 10
104+
```
105+
will terminate (with `VERIFICATION SUCCESSFUL`).
106+
107+
108+
\subsection jbmc-manual-user-assert User assertions
109+
110+
Elaborating on the example above, users may provide their own assertions, that
111+
JBMC will try do refute. Consider the following class:
112+
```java
113+
1 package core;
114+
2
115+
3 public class Example {
116+
4
117+
5 public static void doSomething(int input) {
118+
6 if (input > 1 && input % 2 == 1) {
119+
7 assert isPrime(input);
120+
8 // do something
121+
9 }
122+
10 }
123+
11
124+
12 public static boolean isPrime(int candidate) {
125+
13 for (int div = 2; div * div <= candidate; div++) {
126+
14 if (candidate % div == 0) {
127+
15 return false;
128+
16 }
129+
17 }
130+
18 return candidate > 1;
131+
19 }
132+
20
133+
21 }
134+
```
135+
136+
On line 7, we check the assertion that all odd numbers greater than 1 are prime.
137+
To be sure that this always holds, we run JBMC on the example, with a
138+
reasonable `unwind` value:
139+
```
140+
jbmc Example.class --function core.Example.isPrime --unwind 10
141+
```
142+
and unsurprisingly JBMC doesn't agree, and prints an assertion failure
143+
(truncated here for readability):
144+
```
145+
[...doSomething:(I)V.assertion.1] line 7 assertion at file core/Example.java: FAILURE
146+
```
147+
148+
Rerunning the analysis with the `--trace` option, we can see find out which
149+
input value JBMC found to trigger the violation:
150+
```
151+
INPUT arg0i: 15
152+
```
153+
The value chosen by JBMC is arbitrary, and could as well be 9 or
154+
2084569161.
155+
156+
\subsection jbmc-manual-library Java Library support
157+
158+
The examples above only involve primitive types. In order to analyse code
159+
involving Java Library classes, the core models (located in the same
160+
repository) need to be added to the classpath:
161+
```
162+
--cp <path_to_cbmc>/jbmc/src/java_bytecode/library/core-models.jar
163+
164+
```
165+
The core models library simulate the behaviour of the Java Library and
166+
contains some commonly used classes, such as Object, Class, String, Enum.
167+
Some JBMC-specific utilities reside in the `org.cprover` package.
168+
169+
Using the models, JBMC can reason with a variety of the String operations
170+
from `java.lang.String`, e.g.
171+
172+
```java
173+
5 public static void doSomething() {
174+
6 StringBuilder sb = new StringBuilder("abcd");
175+
7 StringBuilder sb2 = sb.insert(2, "$");
176+
8 assert sb2.toString().startsWith("abc");
177+
9 }
178+
179+
```
180+
The following command line (note that the current directory is also added to
181+
the classpath):
182+
```
183+
jbmc Example.class --function core.Example.doSomething --cp
184+
<path_to_cbmc>/jbmc/src/java_bytecode/library/core-models.jar:.
185+
```
186+
will flag this violation (truncated):
187+
```
188+
[java::core.Example.doSomething:()V.assertion.1] line 8 assertion: FAILURE
189+
```
190+
Again, the trace shows the contradicting string:
191+
```
192+
dynamic_object2={ 'a', 'b', '$', 'c', 'd' }
193+
```
194+
195+
\subsections jbmc-manual-exceptions Exceptions
196+
197+
In its analysis, JBMC can take into account exceptions thrown by user code or
198+
library classes, as well as runtime exceptions such as NullPointerException.
199+
To have JBMC reliably notify about all uncaught exceptions, the
200+
`--throw-runtime-exceptions` can be used.
201+
202+
In the following code, only with `--throw-runtime-exceptions` will JBMC
203+
signal that the assertion on line 11 can be violated. Without that option,
204+
line 11 will be considered as unreachable, and hence the assertion to be valid.
205+
```java
206+
5 public static int exceptionHandling(String str) {
207+
6 int retval = 0;
208+
7 try {
209+
8 retval = str.length();
210+
9 } catch (NullPointerException except) {
211+
10 retval = -1;
212+
11 assert false;
213+
12 }
214+
13 return retval;
215+
14 }
216+
```
217+
218+
To remove all the assertions checking for uncaught exceptions, the
219+
`--disable-uncaught-exception-check` can be used in combination with
220+
`--throw-runtime-exceptions`.
221+
222+
\subsection jbmc-manual-further-doc Further documentation
223+
224+
JBMC has a wealth of other options that can either constrain the model (to
225+
cope with complexity issues), or output more relevant information. The list
226+
of all available options are printed by typing:
227+
```
228+
jbmc --help
229+
```

0 commit comments

Comments
 (0)