CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
java_bytecode_instrument.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Instrument codet with assertions/runtime exceptions
4
5Author: Cristina David
6
7Date: June 2017
8
9\*******************************************************************/
10
12
13#include <util/arith_tools.h>
14#include <util/c_types.h>
15#include <util/std_code.h>
17
19
20#include "java_expr.h"
21#include "java_types.h"
22#include "java_utils.h"
23
25{
26public:
36
37 void operator()(codet &code);
38
39protected:
43
45 const exprt &cond,
47 const irep_idt &exc_name);
48
50 const exprt &array_struct,
51 const exprt &idx,
53
55 const exprt &denominator,
57
59 const exprt &expr,
61
63 const exprt &tested_expr,
64 const struct_tag_typet &target_type,
66
68 const exprt &length,
70
71 void instrument_code(codet &code);
72 void add_expr_instrumentation(code_blockt &block, const exprt &expr);
74 std::optional<codet> instrument_expr(const exprt &expr);
75};
76
77const std::vector<std::string> exception_needed_classes = {
78 "java.lang.ArithmeticException",
79 "java.lang.ArrayIndexOutOfBoundsException",
80 "java.lang.ClassCastException",
81 "java.lang.NegativeArraySizeException",
82 "java.lang.NullPointerException"};
83
94 const exprt &cond,
96 const irep_idt &exc_name)
97{
99
101 {
103 exc_name,
107 }
108
110
111 // Allocate and throw an instance of the exception class:
112
113 symbolt &new_symbol = fresh_java_symbol(
114 exc_ptr_type, "new_exception", original_loc, "new_exception", symbol_table);
115
118
120 throw_expr.copy_to_operands(new_symbol.symbol_expr());
121
124
125 if_code.add_source_location()=original_loc;
126
127 return if_code;
128}
129
138 const exprt &denominator,
140{
141 const constant_exprt &zero=from_integer(0, denominator.type());
142 const binary_relation_exprt equal_zero(denominator, ID_equal, zero);
143
145 return throw_exception(
148 "java.lang.ArithmeticException");
149
151 assertion_loc.set_comment("Denominator should be nonzero");
152 assertion_loc.set_property_class("integer-divide-by-zero");
153
155 binary_relation_exprt(denominator, ID_notequal, zero), assertion_loc);
156}
157
169 const exprt &array_struct,
170 const exprt &idx,
172{
173 const constant_exprt &zero=from_integer(0, java_int_type());
174 const binary_relation_exprt ge_zero(idx, ID_ge, zero);
177 const and_exprt cond(ge_zero, lt_length);
178
180 return throw_exception(
181 not_exprt(cond),
183 "java.lang.ArrayIndexOutOfBoundsException");
184
186
188 low_check_loc.set_comment("Array index should be >= 0");
189 low_check_loc.set_property_class("array-index-out-of-bounds-low");
190
192 high_check_loc.set_comment("Array index should be < length");
193 high_check_loc.set_property_class("array-index-out-of-bounds-high");
194
197
198 return std::move(bounds_checks);
199}
200
212 const exprt &tested_expr,
213 const struct_tag_typet &target_type,
215{
216 java_instanceof_exprt class_cast_check(tested_expr, target_type);
217
220
221 std::optional<codet> check_code;
223 {
228 "java.lang.ClassCastException");
229 }
230 else
231 {
233 check_loc.set_comment("Dynamic cast check");
234 check_loc.set_property_class("bad-dynamic-cast");
235
237
238 check_code=std::move(assert_class);
239 }
240
241 return code_ifthenelset(
243 std::move(*check_code));
244}
245
256 const exprt &expr,
258{
260 expr,
262
264 return throw_exception(
266 original_loc, "java.lang.NullPointerException");
267
269 check_loc.set_comment("Null pointer check");
270 check_loc.set_property_class("null-pointer-exception");
271
273}
274
285 const exprt &length,
287{
288 const constant_exprt &zero=from_integer(0, java_int_type());
289 const binary_relation_exprt ge_zero(length, ID_ge, zero);
290
292 return throw_exception(
295 "java.lang.NegativeArraySizeException");
296
298 check_loc.set_comment("Array size should be >= 0");
299 check_loc.set_property_class("array-create-negative-size");
300
302}
303
309 code_blockt &block,
310 const exprt &expr)
311{
312 if(std::optional<codet> expr_instrumentation = instrument_expr(expr))
313 {
314 if(expr_instrumentation->get_statement() == ID_block)
316 else
317 block.add(std::move(*expr_instrumentation));
318 }
319}
320
326 codet &code,
328{
330 {
331 if(code.get_statement()==ID_block)
332 instrumentation.append(to_code_block(code));
333 else
334 instrumentation.add(code);
335 code=instrumentation;
336 }
337}
338
343{
345
346 const irep_idt &statement=code.get_statement();
347
348 if(statement==ID_assign)
349 {
351
352 code_blockt block;
355 prepend_instrumentation(code, block);
356 }
357 else if(statement==ID_expression)
358 {
360 to_code_expression(code);
361
362 code_blockt block;
363 add_expr_instrumentation(block, code_expression.expression());
364 prepend_instrumentation(code, block);
365 }
366 else if(statement==ID_assert)
367 {
369
370 // does this correspond to checkcast?
371 if(code_assert.assertion().id()==ID_java_instanceof)
372 {
373 code_blockt block;
374 const auto & instanceof
376
377 code = check_class_cast(instanceof.tested_expr(),
379 .target_type(), code_assert.source_location());
380 }
381 }
382 else if(statement==ID_block)
383 {
384 Forall_operands(it, code)
386 }
387 else if(statement==ID_label)
388 {
391 }
392 else if(statement==ID_ifthenelse)
393 {
394 code_blockt block;
397 instrument_code(code_ifthenelse.then_case());
398 if(code_ifthenelse.else_case().is_not_nil())
399 instrument_code(code_ifthenelse.else_case());
400 prepend_instrumentation(code, block);
401 }
402 else if(statement==ID_switch)
403 {
404 code_blockt block;
408 prepend_instrumentation(code, block);
409 }
410 else if(statement==ID_return)
411 {
412 code_blockt block;
414 add_expr_instrumentation(block, code_return.return_value());
415 prepend_instrumentation(code, block);
416 }
417 else if(statement==ID_function_call)
418 {
419 code_blockt block;
423
424 const java_method_typet &function_type =
425 to_java_method_type(code_function_call.function().type());
426
427 for(const auto &arg : code_function_call.arguments())
428 add_expr_instrumentation(block, arg);
429
430 // Check for a null this-argument of a virtual call:
431 if(function_type.has_this())
432 {
434 code_function_call.arguments()[0],
435 code_function_call.source_location()));
436 }
437
438 prepend_instrumentation(code, block);
439 }
440
441 // Ensure source location is retained:
442 if(!old_source_location.get_line().empty())
444}
445
450std::optional<codet>
452{
453 code_blockt result;
454 // First check our operands:
455 for(const auto &op : expr.operands())
456 {
457 if(std::optional<codet> op_result = instrument_expr(op))
458 result.add(std::move(*op_result));
459 }
460
461 // Add any check due at this node:
462 if(expr.id()==ID_plus &&
464 {
465 // this corresponds to ?aload and ?astore so
466 // we check that 0<=index<array.length
467 const plus_exprt &plus_expr=to_plus_expr(expr);
468 if(plus_expr.op0().id()==ID_member)
469 {
471 if(member_expr.compound().id() == ID_dereference)
472 {
473 const dereference_exprt &dereference_expr =
475 codet bounds_check=
477 dereference_expr,
478 plus_expr.op1(),
479 expr.source_location());
480 result.add(std::move(bounds_check));
481 }
482 }
483 }
484 else if(expr.id()==ID_side_effect)
485 {
487 const irep_idt &statement=side_effect_expr.get_statement();
488 if(statement==ID_throw)
489 {
490 // this corresponds to a throw and so we check that
491 // we don't throw null
493 to_unary_expr(expr).op(), expr.source_location()));
494 }
495 else if(statement==ID_java_new_array)
496 {
497 // this corresponds to new array so we check that
498 // length is >=0
499 result.add(check_array_length(
500 to_multi_ary_expr(expr).op0(), expr.source_location()));
501 }
502 }
503 else if((expr.id()==ID_div || expr.id()==ID_mod) &&
504 expr.type().id()==ID_signedbv)
505 {
506 // check division by zero (for integer types only)
508 to_binary_expr(expr).op1(), expr.source_location()));
509 }
510 else if(expr.id()==ID_dereference &&
512 {
513 // Check pointer non-null before access:
514 const dereference_exprt &dereference_expr = to_dereference_expr(expr);
516 dereference_expr.pointer(), dereference_expr.source_location());
517 result.add(std::move(null_dereference_check));
518 }
519
520 if(result==code_blockt())
521 return {};
522 else
523 return std::move(result);
524}
525
532
545 symbol_table_baset &symbol_table,
546 symbolt &symbol,
547 const bool throw_runtime_exceptions,
548 message_handlert &message_handler)
549{
550 java_bytecode_instrumentt instrument(
551 symbol_table,
552 throw_runtime_exceptions,
553 message_handler);
554 INVARIANT(
555 symbol.value.id()==ID_code,
556 "java_bytecode_instrument expects a code-typed symbol but was called with"
557 " " + id2string(symbol.name) + " which has a value with an id of " +
558 id2string(symbol.value.id()));
559 instrument(to_code(symbol.value));
560}
561
569 const symbolt &exc_symbol,
570 const source_locationt &source_location)
571{
572 // check that there is no uncaught exception
574 exc_symbol.symbol_expr(),
576
577 source_locationt assert_location = source_location;
578 assert_location.set_comment("no uncaught exception");
579 assert_no_exception.add_source_location() = assert_location;
580
581 init_code.add(std::move(assert_no_exception));
582}
583
595 symbol_table_baset &symbol_table,
596 const bool throw_runtime_exceptions,
597 message_handlert &message_handler)
598{
599 java_bytecode_instrumentt instrument(
600 symbol_table,
601 throw_runtime_exceptions,
602 message_handler);
603
604 std::vector<irep_idt> symbols_to_instrument;
605 for(const auto &symbol_pair : symbol_table.symbols)
606 {
607 if(symbol_pair.second.value.id() == ID_code)
608 {
609 symbols_to_instrument.push_back(symbol_pair.first);
610 }
611 }
612
613 // instrument(...) can add symbols to the table, so it's
614 // not safe to hold a reference to a symbol across a call.
615 for(const auto &symbol : symbols_to_instrument)
616 {
617 instrument(to_code(symbol_table.get_writeable_ref(symbol).value));
618 }
619}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
pointer_typet pointer_type(const typet &subtype)
Definition c_types.cpp:235
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
Boolean AND.
Definition std_expr.h:2125
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition std_expr.h:762
A non-fatal assertion, which checks a condition then permits execution to continue.
Definition std_code.h:270
A goto_instruction_codet representing an assignment in the program.
A codet representing sequential composition of program statements.
Definition std_code.h:130
void append(const code_blockt &extra_block)
Add all the codets from extra_block to the current code_blockt.
Definition std_code.cpp:86
void add(const codet &code)
Definition std_code.h:168
codet representation of an expression statement.
Definition std_code.h:1394
goto_instruction_codet representation of a function call statement.
codet representation of an if-then-else statement.
Definition std_code.h:460
codet representation of a label for branch targets.
Definition std_code.h:959
goto_instruction_codet representation of a "return from a function" statement.
codet representing a switch statement.
Definition std_code.h:548
bool has_this() const
Definition std_types.h:660
Data structure for representing an arbitrary statement in a program.
const irep_idt & get_statement() const
A constant literal expression.
Definition std_expr.h:3117
Operator to dereference a pointer.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Equality.
Definition std_expr.h:1366
Base class for all expressions.
Definition expr.h:56
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
const source_locationt & source_location() const
Definition expr.h:231
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition irep.h:364
bool get_bool(const irep_idt &name) const
Definition irep.cpp:57
const irep_idt & id() const
Definition irep.h:388
java_bytecode_instrumentt(symbol_table_baset &_symbol_table, const bool _throw_runtime_exceptions, message_handlert &_message_handler)
codet check_array_access(const exprt &array_struct, const exprt &idx, const source_locationt &original_loc)
Checks whether the array access array_struct[idx] is out-of-bounds, and throws ArrayIndexOutofBoundsE...
std::optional< codet > instrument_expr(const exprt &expr)
Computes the instrumentation for expr in the form of either assertions or runtime exceptions.
void operator()(codet &code)
Instruments code.
void prepend_instrumentation(codet &code, code_blockt &instrumentation)
Appends code to instrumentation and overwrites reference code with the augmented block if instrumenta...
void add_expr_instrumentation(code_blockt &block, const exprt &expr)
Checks whether expr requires instrumentation, and if so adds it to block.
codet check_arithmetic_exception(const exprt &denominator, const source_locationt &original_loc)
Checks whether there is a division by zero and throws ArithmeticException if necessary.
codet check_array_length(const exprt &length, const source_locationt &original_loc)
Checks whether length >= 0 and throws NegativeArraySizeException/ generates an assertion when necessa...
void instrument_code(codet &code)
Augments code with instrumentation in the form of either assertions or runtime exceptions.
code_ifthenelset throw_exception(const exprt &cond, const source_locationt &original_loc, const irep_idt &exc_name)
Creates a class stub for exc_name and generates a conditional GOTO such that exc_name is thrown when ...
code_ifthenelset check_class_cast(const exprt &tested_expr, const struct_tag_typet &target_type, const source_locationt &original_loc)
Checks whether class1 is an instance of class2 and throws ClassCastException/generates an assertion w...
codet check_null_dereference(const exprt &expr, const source_locationt &original_loc)
Checks whether expr is null and throws NullPointerException/ generates an assertion when necessary; E...
Extract member of struct or union.
Definition std_expr.h:2971
Boolean negation.
Definition std_expr.h:2454
Disequality.
Definition std_expr.h:1425
The null pointer constant.
The plus expression Associativity is not specified.
Definition std_expr.h:1002
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
A side_effect_exprt representation of a side effect that throws an exception.
Definition std_code.h:1757
An expression containing a side effect.
Definition std_code.h:1450
A struct tag type, i.e., struct_typet with an identifier.
Definition std_types.h:493
std::vector< componentt > componentst
Definition std_types.h:140
The symbol table base class interface.
symbolt & get_writeable_ref(const irep_idt &name)
Find a symbol in the symbol table for read-write access.
const symbolst & symbols
Read-only field, used to look up symbols given their names.
bool has_symbol(const irep_idt &name) const
Check whether a symbol exists in the symbol table.
Symbol table entry.
Definition symbol.h:28
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition symbol.cpp:121
irep_idt name
The unique identifier.
Definition symbol.h:40
exprt value
Initial value of symbol.
Definition symbol.h:34
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2081
The type of an expression, extends irept.
Definition type.h:29
#define Forall_operands(it, expr)
Definition expr.h:27
const code_function_callt & to_code_function_call(const goto_instruction_codet &code)
const code_assignt & to_code_assign(const goto_instruction_codet &code)
const code_returnt & to_code_return(const goto_instruction_codet &code)
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
void java_bytecode_instrument_symbol(symbol_table_baset &symbol_table, symbolt &symbol, const bool throw_runtime_exceptions, message_handlert &message_handler)
Instruments the code attached to symbol with runtime exceptions or corresponding assertions.
void java_bytecode_instrument_uncaught_exceptions(code_blockt &init_code, const symbolt &exc_symbol, const source_locationt &source_location)
Instruments the start function with an assertion that checks whether an exception has escaped the ent...
void java_bytecode_instrument(symbol_table_baset &symbol_table, const bool throw_runtime_exceptions, message_handlert &message_handler)
Instruments all the code in the symbol_table with runtime exceptions or corresponding assertions.
const std::vector< std::string > exception_needed_classes
Java-specific exprt subclasses.
const java_instanceof_exprt & to_java_instanceof_expr(const exprt &expr)
Cast an exprt to a java_instanceof_exprt.
Definition java_expr.h:86
signedbv_typet java_int_type()
empty_typet java_void_type()
const java_method_typet & to_java_method_type(const typet &type)
Definition java_types.h:183
void generate_class_stub(const irep_idt &class_name, symbol_table_baset &symbol_table, message_handlert &message_handler, const struct_union_typet::componentst &componentst)
symbolt & fresh_java_symbol(const typet &type, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &function_name, symbol_table_baset &symbol_table)
void merge_source_location_rec(exprt &expr, const source_locationt &source_location)
Attaches a source location to an expression and all of its subexpressions.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
code_blockt create_fatal_assertion(const exprt &condition, const source_locationt &loc)
Create a fatal assertion, which checks a condition and then halts if it does not hold.
Definition std_code.cpp:120
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition std_code.h:1506
const code_assertt & to_code_assert(const codet &code)
Definition std_code.h:304
const code_labelt & to_code_label(const codet &code)
Definition std_code.h:1004
const code_blockt & to_code_block(const codet &code)
Definition std_code.h:203
const code_ifthenelset & to_code_ifthenelse(const codet &code)
Definition std_code.h:530
const code_switcht & to_code_switch(const codet &code)
Definition std_code.h:592
code_expressiont & to_code_expression(codet &code)
Definition std_code.h:1428
const codet & to_code(const exprt &expr)
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition std_expr.h:715
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition std_expr.h:1041
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition std_expr.h:426
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition std_expr.h:987
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3063
Author: Diffblue Ltd.
void check_code(const codet &code, const validation_modet vm)
Check that the given code statement is well-formed (shallow checks only, i.e., enclosed statements,...