CBMC
simple_method_stubbing.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Simple Java method stubbing
4 
5 Author: Diffblue Ltd.
6 
7 \*******************************************************************/
8 
11 
12 #include "simple_method_stubbing.h"
13 
18 
19 #include "java_utils.h"
20 #include <util/invariant_utils.h>
21 #include <util/namespace.h>
22 #include <util/std_code.h>
23 #include <util/symbol_table_base.h>
24 
26 {
27 public:
29  symbol_table_baset &_symbol_table,
30  bool _assume_non_null,
31  const java_object_factory_parameterst &_object_factory_parameters,
32  message_handlert &_message_handler)
33  : symbol_table(_symbol_table),
34  assume_non_null(_assume_non_null),
35  object_factory_parameters(_object_factory_parameters),
36  message_handler(_message_handler)
37  {
38  }
39 
41  const typet &expected_type,
42  const exprt &ptr,
43  const source_locationt &loc,
44  const irep_idt &function_id,
45  code_blockt &parent_block,
46  unsigned insert_before_index,
47  bool is_constructor,
48  bool update_in_place);
49 
50  void create_method_stub(symbolt &symbol);
51 
52  void check_method_stub(const irep_idt &);
53 
54 protected:
59 };
60 
82  const typet &expected_type,
83  const exprt &ptr,
84  const source_locationt &loc,
85  const irep_idt &function_id,
86  code_blockt &parent_block,
87  const unsigned insert_before_index,
88  const bool is_constructor,
89  const bool update_in_place)
90 {
91  // At this point we know 'ptr' points to an opaque-typed object.
92  // We should nondet-initialize it and insert the instructions *after*
93  // the offending call at (*parent_block)[insert_before_index].
94 
96  expected_type.id() == ID_pointer,
97  "Nondet initializer result type: expected a pointer",
98  expected_type);
99 
101 
102  const auto &expected_base =
103  ns.follow(to_pointer_type(expected_type).base_type());
104  if(expected_base.id() != ID_struct)
105  return;
106 
107  const exprt cast_ptr =
108  make_clean_pointer_cast(ptr, to_pointer_type(expected_type), ns);
109 
110  exprt to_init = cast_ptr;
111  // If it's a constructor the thing we're constructing has already
112  // been allocated by this point.
113  if(is_constructor)
114  to_init = dereference_exprt(to_init);
115 
117  if(assume_non_null)
118  parameters.min_null_tree_depth = 1;
119 
120  // Generate new instructions.
121  code_blockt new_instructions;
122  parameters.function_id = function_id;
124  to_init,
125  new_instructions,
126  symbol_table,
127  loc,
130  parameters,
134 
135  // Insert new_instructions into parent block.
136  if(!new_instructions.statements().empty())
137  {
138  auto insert_position = parent_block.statements().begin();
139  std::advance(insert_position, insert_before_index);
140  parent_block.statements().insert(
141  insert_position,
142  new_instructions.statements().begin(),
143  new_instructions.statements().end());
144  }
145 }
146 
152 {
153  code_blockt new_instructions;
154  java_method_typet &required_type = to_java_method_type(symbol.type);
155 
156  // synthetic source location that contains the opaque function name only
157  source_locationt synthesized_source_location;
158  synthesized_source_location.set_function(symbol.name);
159 
160  // make sure all parameters are named
161  for(auto &parameter : required_type.parameters())
162  {
163  if(parameter.get_identifier().empty())
164  {
165  symbolt &parameter_symbol = fresh_java_symbol(
166  parameter.type(),
167  "#anon",
168  synthesized_source_location,
169  symbol.name,
170  symbol_table);
171  parameter_symbol.is_parameter = true;
172  parameter.set_base_name(parameter_symbol.base_name);
173  parameter.set_identifier(parameter_symbol.name);
174  }
175  }
176 
177  // Initialize the return value or `this` parameter under construction.
178  // Note symbol.type is required_type, but with write access
179  // Probably required_type should not be const
180  const bool is_constructor = required_type.get_is_constructor();
181  if(is_constructor)
182  {
183  const auto &this_argument = required_type.parameters()[0];
184  const typet &this_type = this_argument.type();
186  this_type,
187  "to_construct",
188  synthesized_source_location,
189  symbol.name,
190  symbol_table);
191  const symbol_exprt &init_symbol_expression = init_symbol.symbol_expr();
192  code_frontend_assignt get_argument(
193  init_symbol_expression,
194  symbol_exprt(this_argument.get_identifier(), this_type));
195  get_argument.add_source_location() = synthesized_source_location;
196  new_instructions.add(get_argument);
198  this_type,
199  init_symbol_expression,
200  synthesized_source_location,
201  symbol.name,
202  new_instructions,
203  1,
204  true,
205  false);
206  }
207  else
208  {
209  const typet &required_return_type = required_type.return_type();
210  if(required_return_type != java_void_type())
211  {
212  symbolt &to_return_symbol = fresh_java_symbol(
213  required_return_type,
214  "to_return",
215  synthesized_source_location,
216  symbol.name,
217  symbol_table);
218  const exprt &to_return = to_return_symbol.symbol_expr();
219  if(to_return_symbol.type.id() != ID_pointer)
220  {
222  if(assume_non_null)
223  parameters.min_null_tree_depth = 1;
224 
226  to_return,
227  new_instructions,
228  symbol_table,
230  false,
231  lifetimet::AUTOMATIC_LOCAL, // Irrelevant as type is primitive
232  parameters,
235  }
236  else
238  required_return_type,
239  to_return,
240  synthesized_source_location,
241  symbol.name,
242  new_instructions,
243  0,
244  false,
245  false);
246  new_instructions.add(code_frontend_returnt(to_return));
247  }
248  }
249 
250  symbol.value = new_instructions;
251 }
252 
257 {
258  const symbolt &sym = symbol_table.lookup_ref(symname);
259  if(!sym.is_type && sym.value.id() == ID_nil &&
260  sym.type.id() == ID_code &&
261  // do not stub internal locking calls as 'create_method_stub' does not
262  // automatically create the appropriate symbols for the formal parameters.
263  // This means that symex will (rightfully) crash when it encounters the
264  // function call as it will not be able to find symbols for the fromal
265  // parameters.
266  sym.name !=
267  "java::java.lang.Object.monitorenter:(Ljava/lang/Object;)V" &&
268  sym.name !=
269  "java::java.lang.Object.monitorexit:(Ljava/lang/Object;)V")
270  {
272  }
273 }
274 
276  const irep_idt &function_name,
277  symbol_table_baset &symbol_table,
278  bool assume_non_null,
279  const java_object_factory_parameterst &object_factory_parameters,
280  message_handlert &message_handler)
281 {
282  java_simple_method_stubst stub_generator(
283  symbol_table, assume_non_null, object_factory_parameters, message_handler);
284 
285  stub_generator.check_method_stub(function_name);
286 }
287 
298  symbol_table_baset &symbol_table,
299  bool assume_non_null,
300  const java_object_factory_parameterst &object_factory_parameters,
301  message_handlert &message_handler)
302 {
303  // The intent here is to apply stub_generator.check_method_stub() to
304  // all the identifiers in the symbol table. However this method may alter the
305  // symbol table and iterating over a container which is being modified has
306  // undefined behaviour. Therefore in order for this to work reliably, we must
307  // take a copy of the identifiers in the symbol table and iterate over that,
308  // instead of iterating over the symbol table itself.
309  std::vector<irep_idt> identifiers;
310  identifiers.reserve(symbol_table.symbols.size());
311  for(const auto &symbol : symbol_table)
312  identifiers.push_back(symbol.first);
313 
314  java_simple_method_stubst stub_generator(
315  symbol_table, assume_non_null, object_factory_parameters, message_handler);
316 
317  for(const auto &identifier : identifiers)
318  {
319  stub_generator.check_method_stub(identifier);
320  }
321 }
java_simple_method_stubst::assume_non_null
bool assume_non_null
Definition: simple_method_stubbing.cpp:56
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
code_blockt
A codet representing sequential composition of program statements.
Definition: std_code.h:129
java_simple_method_stubst
Definition: simple_method_stubbing.cpp:25
symbol_table_baset::lookup_ref
const symbolt & lookup_ref(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
Definition: symbol_table_base.h:104
java_simple_method_stubst::message_handler
message_handlert & message_handler
Definition: simple_method_stubbing.cpp:58
source_locationt::set_function
void set_function(const irep_idt &function)
Definition: source_location.h:120
lifetimet::AUTOMATIC_LOCAL
@ AUTOMATIC_LOCAL
Allocate local objects with automatic lifetime.
typet
The type of an expression, extends irept.
Definition: type.h:28
symbolt::type
typet type
Type of symbol.
Definition: symbol.h:31
dereference_exprt
Operator to dereference a pointer.
Definition: pointer_expr.h:659
object_factory_parameterst::function_id
irep_idt function_id
Function id, used as a prefix for identifiers of temporaries.
Definition: object_factory_parameters.h:79
java_generate_simple_method_stubs
void java_generate_simple_method_stubs(symbol_table_baset &symbol_table, bool assume_non_null, const java_object_factory_parameterst &object_factory_parameters, message_handlert &message_handler)
Generates function stubs for most undefined functions in the symbol table, except as forbidden in jav...
Definition: simple_method_stubbing.cpp:297
java_simple_method_stubst::check_method_stub
void check_method_stub(const irep_idt &)
Replaces sym with a function stub per the function above if it is of suitable type.
Definition: simple_method_stubbing.cpp:256
exprt
Base class for all expressions.
Definition: expr.h:55
make_clean_pointer_cast
exprt make_clean_pointer_cast(const exprt &rawptr, const pointer_typet &target_type, const namespacet &ns)
Definition: java_pointer_casts.cpp:72
symbolt::base_name
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:46
java_object_factory_parameters.h
symbol_exprt
Expression to hold a symbol (variable)
Definition: std_expr.h:112
namespace.h
simple_method_stubbing.h
code_typet::get_is_constructor
bool get_is_constructor() const
Definition: std_types.h:685
java_simple_method_stubst::java_simple_method_stubst
java_simple_method_stubst(symbol_table_baset &_symbol_table, bool _assume_non_null, const java_object_factory_parameterst &_object_factory_parameters, message_handlert &_message_handler)
Definition: simple_method_stubbing.cpp:28
update_in_placet::MUST_UPDATE_IN_PLACE
@ MUST_UPDATE_IN_PLACE
code_blockt::statements
code_operandst & statements()
Definition: std_code.h:138
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
java_pointer_casts.h
java_simple_method_stubst::create_method_stub_at
void create_method_stub_at(const typet &expected_type, const exprt &ptr, const source_locationt &loc, const irep_idt &function_id, code_blockt &parent_block, unsigned insert_before_index, bool is_constructor, bool update_in_place)
Nondet-initialize an object, including allocating referees for reference fields and nondet-initialisi...
Definition: simple_method_stubbing.cpp:81
init_symbol
static std::unordered_set< irep_idt > init_symbol(const symbolt &sym, code_blockt &code_block, symbol_table_baset &symbol_table, const source_locationt &source_location, bool assume_init_pointers_not_null, const java_object_factory_parameterst &object_factory_parameters, const select_pointer_typet &pointer_type_selector, bool string_refinement_enabled, message_handlert &message_handler)
Definition: java_entry_point.cpp:109
java_object_factory.h
symbol_table_baset::get_writeable_ref
symbolt & get_writeable_ref(const irep_idt &name)
Find a symbol in the symbol table for read-write access.
Definition: symbol_table_base.h:121
symbol_table_baset
The symbol table base class interface.
Definition: symbol_table_base.h:21
java_simple_method_stubst::create_method_stub
void create_method_stub(symbolt &symbol)
Replaces sym's value with an opaque method stub.
Definition: simple_method_stubbing.cpp:151
symbolt::symbol_expr
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
to_pointer_type
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:79
code_frontend_assignt
A codet representing an assignment in the program.
Definition: std_code.h:23
gen_nondet_init
void gen_nondet_init(const exprt &expr, code_blockt &init_code, symbol_table_baset &symbol_table, const source_locationt &loc, bool skip_classid, lifetimet lifetime, const java_object_factory_parameterst &object_factory_parameters, const select_pointer_typet &pointer_type_selector, update_in_placet update_in_place, message_handlert &log)
Initializes a primitive-typed or reference-typed object tree rooted at expr, allocating child objects...
Definition: java_object_factory.cpp:1624
symbolt::is_parameter
bool is_parameter
Definition: symbol.h:67
irept::id
const irep_idt & id() const
Definition: irep.h:396
message_handlert
Definition: message.h:27
code_blockt::add
void add(const codet &code)
Definition: std_code.h:168
code_typet::parameters
const parameterst & parameters() const
Definition: std_types.h:655
std_code.h
fresh_java_symbol
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)
Definition: java_utils.cpp:558
object_factory_parameterst::min_null_tree_depth
size_t min_null_tree_depth
To force a certain depth of non-null objects.
Definition: object_factory_parameters.h:70
code_frontend_returnt
codet representation of a "return from a function" statement.
Definition: std_code.h:892
source_locationt
Definition: source_location.h:18
invariant_utils.h
symbolt::value
exprt value
Initial value of symbol.
Definition: symbol.h:34
java_generate_simple_method_stub
void java_generate_simple_method_stub(const irep_idt &function_name, symbol_table_baset &symbol_table, bool assume_non_null, const java_object_factory_parameterst &object_factory_parameters, message_handlert &message_handler)
Definition: simple_method_stubbing.cpp:275
java_simple_method_stubst::symbol_table
symbol_table_baset & symbol_table
Definition: simple_method_stubbing.cpp:55
namespace_baset::follow
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
symbolt
Symbol table entry.
Definition: symbol.h:27
symbol_table_baset::symbols
const symbolst & symbols
Read-only field, used to look up symbols given their names.
Definition: symbol_table_base.h:30
symbolt::is_type
bool is_type
Definition: symbol.h:61
update_in_placet::NO_UPDATE_IN_PLACE
@ NO_UPDATE_IN_PLACE
lifetimet::DYNAMIC
@ DYNAMIC
Allocate dynamic objects (using ALLOCATE)
code_typet::return_type
const typet & return_type() const
Definition: std_types.h:645
java_types.h
exprt::add_source_location
source_locationt & add_source_location()
Definition: expr.h:216
symbol_table_base.h
Author: Diffblue Ltd.
to_java_method_type
const java_method_typet & to_java_method_type(const typet &type)
Definition: java_types.h:184
java_void_type
empty_typet java_void_type()
Definition: java_types.cpp:37
is_constructor
static bool is_constructor(const irep_idt &method_name)
Definition: java_bytecode_convert_method.cpp:121
java_utils.h
java_method_typet
Definition: java_types.h:100
java_object_factory_parameterst
Definition: java_object_factory_parameters.h:15
symbolt::name
irep_idt name
The unique identifier.
Definition: symbol.h:40
java_simple_method_stubst::object_factory_parameters
const java_object_factory_parameterst & object_factory_parameters
Definition: simple_method_stubbing.cpp:57
INVARIANT_WITH_IREP
#define INVARIANT_WITH_IREP(CONDITION, DESCRIPTION, IREP)
Equivalent to INVARIANT_STRUCTURED(CONDITION, invariant_failedt, pretty_print_invariant_with_irep(IRE...
Definition: invariant_utils.h:30