CBMC
link_goto_model.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Link Goto Programs
4 
5 Author: Michael Tautschnig, Daniel Kroening
6 
7 \*******************************************************************/
8 
11 
12 #include "link_goto_model.h"
13 #include <linking/linking_class.h>
14 
15 #include <util/message.h>
16 #include <util/rename_symbol.h>
17 #include <util/symbol.h>
18 
19 #include "goto_model.h"
20 
21 #include <unordered_set>
22 
25  const rename_symbolt &rename_symbol)
26 {
27  for(auto &identifier : function.parameter_identifiers)
28  {
29  auto entry = rename_symbol.expr_map.find(identifier);
30  if(entry != rename_symbol.expr_map.end())
31  identifier = entry->second;
32  }
33 
34  for(auto &instruction : function.body.instructions)
35  {
36  rename_symbol(instruction.code_nonconst());
37 
38  if(instruction.has_condition())
39  rename_symbol(instruction.condition_nonconst());
40  }
41 }
42 
45 static bool link_functions(
46  symbol_tablet &dest_symbol_table,
47  goto_functionst &dest_functions,
48  const symbol_tablet &src_symbol_table,
49  goto_functionst &src_functions,
50  const rename_symbolt &rename_dest_symbol,
51  const rename_symbolt &rename_src_symbol,
52  const std::unordered_set<irep_idt> &weak_symbols)
53 {
54  namespacet ns(dest_symbol_table);
55  namespacet src_ns(src_symbol_table);
56 
57  // rename existing functions if linking requires us to do so
58  for(const auto &rename_entry : rename_dest_symbol.expr_map)
59  {
60  auto fn_candidate = dest_functions.function_map.find(rename_entry.first);
61  if(fn_candidate == dest_functions.function_map.end())
62  continue;
63 
64  dest_functions.function_map.insert(
65  {rename_entry.second, std::move(fn_candidate->second)});
66  dest_functions.function_map.erase(fn_candidate);
67  }
68 
69  // rename symbols in existing functions
70  for(auto &dest_entry : dest_functions.function_map)
71  rename_symbols_in_function(dest_entry.second, rename_dest_symbol);
72 
73  // merge functions
74  for(auto &gf_entry : src_functions.function_map)
75  {
76  // the function might have been renamed
77  rename_symbolt::expr_mapt::const_iterator e_it =
78  rename_src_symbol.expr_map.find(gf_entry.first);
79 
80  irep_idt final_id = gf_entry.first;
81 
82  if(e_it != rename_src_symbol.expr_map.end())
83  final_id=e_it->second;
84 
85  // already there?
86  goto_functionst::function_mapt::iterator dest_f_it=
87  dest_functions.function_map.find(final_id);
88 
89  goto_functionst::goto_functiont &src_func = gf_entry.second;
90  if(dest_f_it==dest_functions.function_map.end()) // not there yet
91  {
92  rename_symbols_in_function(src_func, rename_src_symbol);
93  dest_functions.function_map.emplace(final_id, std::move(src_func));
94  }
95  else // collision!
96  {
97  goto_functionst::goto_functiont &in_dest_symbol_table = dest_f_it->second;
98 
99  if(in_dest_symbol_table.body.instructions.empty() ||
100  weak_symbols.find(final_id)!=weak_symbols.end())
101  {
102  // the one with body wins!
103  rename_symbols_in_function(src_func, rename_src_symbol);
104 
105  in_dest_symbol_table.body.swap(src_func.body);
106  in_dest_symbol_table.parameter_identifiers.swap(
107  src_func.parameter_identifiers);
108  }
109  else if(
110  src_func.body.instructions.empty() ||
111  src_ns.lookup(gf_entry.first).is_weak)
112  {
113  // just keep the old one in dest
114  }
115  else if(to_code_type(ns.lookup(final_id).type).get_inlined())
116  {
117  // ok, we silently ignore
118  }
119  }
120  }
121 
122  return false;
123 }
124 
125 std::optional<replace_symbolt::expr_mapt> link_goto_model(
126  goto_modelt &dest,
127  goto_modelt &&src,
128  message_handlert &message_handler)
129 {
130  std::unordered_set<irep_idt> weak_symbols;
131 
132  for(const auto &symbol_pair : dest.symbol_table.symbols)
133  {
134  if(symbol_pair.second.is_weak)
135  weak_symbols.insert(symbol_pair.first);
136  }
137 
138  linkingt linking(dest.symbol_table, message_handler);
139 
140  if(linking.link(src.symbol_table))
141  {
142  messaget log{message_handler};
143  log.error() << "typechecking main failed" << messaget::eom;
144  return {};
145  }
146 
147  if(link_functions(
148  dest.symbol_table,
149  dest.goto_functions,
150  src.symbol_table,
151  src.goto_functions,
152  linking.rename_main_symbol,
153  linking.rename_new_symbol,
154  weak_symbols))
155  {
156  messaget log{message_handler};
157  log.error() << "linking failed" << messaget::eom;
158  return {};
159  }
160 
161  return linking.object_type_updates.get_expr_map();
162 }
163 
165  goto_modelt &dest,
166  const replace_symbolt::expr_mapt &type_updates)
167 {
168  casting_replace_symbolt object_type_updates;
169  object_type_updates.get_expr_map().insert(
170  type_updates.begin(), type_updates.end());
171 
172  goto_functionst &dest_functions = dest.goto_functions;
173  symbol_tablet &dest_symbol_table = dest.symbol_table;
174 
175  // apply macros
176  rename_symbolt macro_application;
177 
178  for(const auto &symbol_pair : dest_symbol_table.symbols)
179  {
180  if(symbol_pair.second.is_macro && !symbol_pair.second.is_type)
181  {
182  const symbolt &symbol = symbol_pair.second;
183 
184  INVARIANT(symbol.value.id() == ID_symbol, "must have symbol");
185  const irep_idt &id = to_symbol_expr(symbol.value).get_identifier();
186 
187  #if 0
188  if(!base_type_eq(symbol.type, ns.lookup(id).type, ns))
189  {
190  std::cerr << symbol << '\n';
191  std::cerr << ns.lookup(id) << '\n';
192  }
193  INVARIANT(base_type_eq(symbol.type, ns.lookup(id).type, ns),
194  "type matches");
195  #endif
196 
197  macro_application.insert_expr(symbol.name, id);
198  }
199  }
200 
201  if(!macro_application.expr_map.empty())
202  {
203  for(auto &gf_entry : dest_functions.function_map)
204  rename_symbols_in_function(gf_entry.second, macro_application);
205  }
206 
207  if(!object_type_updates.empty())
208  {
209  for(auto &gf_entry : dest_functions.function_map)
210  {
211  for(auto &instruction : gf_entry.second.body.instructions)
212  {
213  if(instruction.is_function_call())
214  {
215  const bool changed =
216  !object_type_updates.replace(instruction.call_function());
217  if(changed && instruction.call_lhs().is_not_nil())
218  {
219  object_type_updates(instruction.call_lhs());
220  if(
221  instruction.call_lhs().type() !=
222  to_code_type(instruction.call_function().type()).return_type())
223  {
224  instruction.call_lhs() = typecast_exprt{
225  instruction.call_lhs(),
226  to_code_type(instruction.call_function().type()).return_type()};
227  }
228  }
229  }
230  else
231  {
232  instruction.transform([&object_type_updates](exprt expr) {
233  const bool changed = !object_type_updates.replace(expr);
234  return changed ? std::optional<exprt>{expr} : std::nullopt;
235  });
236  }
237  }
238  }
239  }
240 }
A variant of replace_symbolt that does not require types to match, but instead inserts type casts as ...
bool replace(exprt &dest) const override
const typet & return_type() const
Definition: std_types.h:689
bool get_inlined() const
Definition: std_types.h:709
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Base class for all expressions.
Definition: expr.h:56
A collection of goto functions.
function_mapt function_map
::goto_functiont goto_functiont
symbol_tablet symbol_table
Symbol table.
Definition: goto_model.h:31
goto_functionst goto_functions
GOTO functions.
Definition: goto_model.h:34
const irep_idt & id() const
Definition: irep.h:388
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:154
static eomt eom
Definition: message.h:289
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
expr_mapt expr_map
Definition: rename_symbol.h:63
void insert_expr(const irep_idt &old_id, const irep_idt &new_id)
Definition: rename_symbol.h:31
bool empty() const
const expr_mapt & get_expr_map() const
std::unordered_map< irep_idt, exprt > expr_mapt
const irep_idt & get_identifier() const
Definition: std_expr.h:160
const symbolst & symbols
Read-only field, used to look up symbols given their names.
The symbol table.
Definition: symbol_table.h:14
Symbol table entry.
Definition: symbol.h:28
typet type
Type of symbol.
Definition: symbol.h:31
irep_idt name
The unique identifier.
Definition: symbol.h:40
exprt value
Initial value of symbol.
Definition: symbol.h:34
Semantic type conversion.
Definition: std_expr.h:2073
Symbol Table + CFG.
bool linking(symbol_table_baset &dest_symbol_table, const symbol_table_baset &new_symbol_table, message_handlert &message_handler)
Merges the symbol table new_symbol_table into dest_symbol_table, renaming symbols from new_symbol_tab...
Definition: linking.cpp:1130
ANSI-C Linking.
double log(double x)
Definition: math.c:2776
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition: invariant.h:423
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:788
Symbol table entry.