|
| 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