|
| 1 | +/*******************************************************************\ |
| 2 | + Module: Unit tests for module remove_function_pointers.refine_call_type |
| 3 | +
|
| 4 | + Author: Diffblue Ltd. |
| 5 | +
|
| 6 | + Date: May 2019 |
| 7 | +
|
| 8 | +\*******************************************************************/ |
| 9 | + |
| 10 | +/// \file |
| 11 | +/// Unit tests for module remove_function_pointers |
| 12 | + |
| 13 | +#include <testing-utils/message.h> |
| 14 | +#include <testing-utils/use_catch.h> |
| 15 | + |
| 16 | +#include <util/arith_tools.h> |
| 17 | +#include <util/c_types.h> |
| 18 | +#include <util/std_code.h> |
| 19 | + |
| 20 | +#include <goto-programs/goto_convert_functions.h> |
| 21 | +#include <goto-programs/goto_model.h> |
| 22 | +#include <goto-programs/remove_function_pointers.h> |
| 23 | + |
| 24 | +SCENARIO( |
| 25 | + "List potential targets works for ellipsis", |
| 26 | + "[core][goto-programs][list_potential_targets]") |
| 27 | +{ |
| 28 | + goto_modelt goto_model; |
| 29 | + // create one instance of the function type, they are all |
| 30 | + // going to have the same signature |
| 31 | + |
| 32 | + symbolt int_param; |
| 33 | + int_param.name = "int_param"; |
| 34 | + int_param.mode = ID_C; |
| 35 | + int_param.type = signedbv_typet{32}; |
| 36 | + goto_model.symbol_table.add(int_param); |
| 37 | + |
| 38 | + code_typet::parameterst parameters; |
| 39 | + parameters.emplace_back(signedbv_typet{32}); |
| 40 | + parameters.back().set_identifier("int_param"); |
| 41 | + auto func_empty_type = code_typet{{}, empty_typet{}}; |
| 42 | + auto func_ellipsis_type = code_typet{{}, empty_typet{}}; |
| 43 | + func_ellipsis_type.make_ellipsis(); |
| 44 | + auto func_one_arg_type = code_typet{parameters, empty_typet{}}; |
| 45 | + // create an empty code block, to act as the functions' body |
| 46 | + code_blockt func_body = code_blockt{}; |
| 47 | + |
| 48 | + irep_idt f_name{"f"}; |
| 49 | + |
| 50 | + // void f(...){}; |
| 51 | + symbolt f; |
| 52 | + f.name = f_name; |
| 53 | + f.mode = ID_C; |
| 54 | + f.type = func_ellipsis_type; // takes anything |
| 55 | + f.value = func_body; |
| 56 | + goto_model.symbol_table.add(f); |
| 57 | + |
| 58 | + // void g(int){}; |
| 59 | + symbolt g; |
| 60 | + g.name = "g"; |
| 61 | + g.mode = ID_C; |
| 62 | + g.type = func_one_arg_type; // takes one int |
| 63 | + g.value = func_body; |
| 64 | + goto_model.symbol_table.add(g); |
| 65 | + |
| 66 | + // create array with function pointer elements |
| 67 | + array_typet fp_array_type( |
| 68 | + pointer_typet{func_ellipsis_type, 64}, from_integer(2, index_type())); |
| 69 | + array_exprt fp_array{{}, fp_array_type}; |
| 70 | + |
| 71 | + fp_array.copy_to_operands(address_of_exprt{f.symbol_expr()}); |
| 72 | + fp_array.copy_to_operands(address_of_exprt{g.symbol_expr()}); |
| 73 | + |
| 74 | + // fpa = fparray {f1, f2}; |
| 75 | + symbolt fpa; |
| 76 | + fpa.name = "fpa"; |
| 77 | + fpa.mode = ID_C; |
| 78 | + fpa.type = fp_array_type; |
| 79 | + fpa.value = fp_array; |
| 80 | + |
| 81 | + goto_model.symbol_table.add(fpa); |
| 82 | + |
| 83 | + irep_idt fn_ptr_name{"fn_ptr"}; |
| 84 | + |
| 85 | + // pointer to fn call |
| 86 | + symbolt fn_ptr; |
| 87 | + fn_ptr.name = fn_ptr_name; |
| 88 | + fn_ptr.mode = ID_C; |
| 89 | + fn_ptr.type = pointer_typet{func_ellipsis_type, 64}; |
| 90 | + goto_model.symbol_table.add(fn_ptr); |
| 91 | + |
| 92 | + // symbol for indexing the array |
| 93 | + symbolt z; |
| 94 | + z.name = "z"; |
| 95 | + z.mode = ID_C; |
| 96 | + z.type = index_type(); |
| 97 | + goto_model.symbol_table.add(z); |
| 98 | + |
| 99 | + // create function with pointer function call instruction |
| 100 | + |
| 101 | + // void entry(){z; array; fn_ptr = array[z]; *fn_ptr(z)}; |
| 102 | + symbolt entry; |
| 103 | + entry.name = "entry"; |
| 104 | + entry.mode = ID_C; |
| 105 | + entry.type = func_empty_type; |
| 106 | + |
| 107 | + code_function_callt::argumentst arguments; |
| 108 | + arguments.emplace_back(z.symbol_expr()); |
| 109 | + |
| 110 | + code_blockt entry_body{ |
| 111 | + {// fn_ptr = array[z]; |
| 112 | + code_assignt{fn_ptr.symbol_expr(), |
| 113 | + index_exprt{fp_array, |
| 114 | + z.symbol_expr(), |
| 115 | + pointer_type(func_ellipsis_type)}}, |
| 116 | + // *fn_ptr(); |
| 117 | + code_function_callt{dereference_exprt{fn_ptr.symbol_expr()}, arguments}}}; |
| 118 | + entry.value = entry_body; |
| 119 | + goto_model.symbol_table.add(entry); |
| 120 | + |
| 121 | + WHEN("list_potential_targets is run") |
| 122 | + { |
| 123 | + goto_convert(goto_model, null_message_handler); |
| 124 | + |
| 125 | + // goto convert removes ellipsis so we need to re-insert them |
| 126 | + auto &f_symbol = goto_model.symbol_table.get_writeable_ref(f_name); |
| 127 | + to_code_type(f_symbol.type).make_ellipsis(); |
| 128 | + auto &fn_ptr_symbol = |
| 129 | + goto_model.symbol_table.get_writeable_ref(fn_ptr_name); |
| 130 | + to_code_type(fn_ptr_symbol.type.subtype()).make_ellipsis(); |
| 131 | + |
| 132 | + auto &goto_functions = goto_model.goto_functions; |
| 133 | + for(auto &goto_function_pair : goto_functions.function_map) |
| 134 | + { |
| 135 | + auto &goto_function = goto_function_pair.second; |
| 136 | + auto &goto_program = goto_function.body; |
| 137 | + for(auto &instruction : goto_program.instructions) |
| 138 | + { |
| 139 | + if(instruction.is_function_call()) |
| 140 | + { |
| 141 | + code_function_callt function_call = instruction.get_function_call(); |
| 142 | + auto &function = to_dereference_expr(function_call.function()); |
| 143 | + to_code_type(function.type()).make_ellipsis(); |
| 144 | + instruction.set_function_call(function_call); |
| 145 | + } |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + auto target_map = |
| 150 | + get_function_pointer_targets(null_message_handler, goto_model); |
| 151 | + THEN("there should be 4 targets recognised") |
| 152 | + { |
| 153 | + REQUIRE(target_map.size() == 1); |
| 154 | + REQUIRE(target_map.begin()->second.size() == 2); |
| 155 | + } |
| 156 | + } |
| 157 | +} |
0 commit comments