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