Skip to content

Commit 51da31b

Browse files
Merge pull request diffblue#5 from thk123/feature/c-opaque-method-stubs
Implementing getting the method stub generation for C
2 parents 2f09338 + 410b5e8 commit 51da31b

File tree

4 files changed

+318
-0
lines changed

4 files changed

+318
-0
lines changed

src/ansi-c/ansi_c_language.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Author: Daniel Kroening, [email protected]
1313
#include <util/expr_util.h>
1414
#include <util/config.h>
1515
#include <util/get_base_name.h>
16+
#include <util/symbol.h>
1617

1718
#include <linking/linking.h>
1819
#include <linking/remove_internal_symbols.h>
@@ -65,6 +66,103 @@ void ansi_c_languaget::modules_provided(std::set<std::string> &modules)
6566

6667
/*******************************************************************\
6768
69+
Function: ansi_c_languaget::generate_opaque_stub_body
70+
71+
Inputs:
72+
symbol - the function symbol which is opaque
73+
symbol_table - the symbol table
74+
75+
Outputs: The identifier of the return variable. ID_nil if the function
76+
doesn't return anything.
77+
78+
Purpose: To generate the stub function for the opaque function in
79+
question. The identifier is used in the flag to the interpreter
80+
that the function is opaque. In C, providing the function returns
81+
something, the id will be to_return_function_name.
82+
The GOTO code will simply create a NONDET instruction as the
83+
return value.
84+
85+
\*******************************************************************/
86+
87+
irep_idt ansi_c_languaget::generate_opaque_stub_body(
88+
symbolt &symbol,
89+
symbol_tablet &symbol_table)
90+
{
91+
code_blockt new_instructions;
92+
code_typet &function_type=to_code_type(symbol.type);
93+
const typet &return_type=function_type.return_type();
94+
95+
if(return_type.id()!=ID_nil)
96+
{
97+
// Build an auxillary symbol to store the return value for
98+
// this function
99+
auxiliary_symbolt return_symbol;
100+
return_symbol.name=get_stub_return_symbol_name(symbol.name);
101+
return_symbol.base_name=return_symbol.name;
102+
return_symbol.mode=ID_C;
103+
return_symbol.type=return_type;
104+
105+
// Put this symbol into the symbol table
106+
symbolt *symbol_ptr=nullptr;
107+
symbol_table.move(return_symbol, symbol_ptr);
108+
assert(symbol_ptr);
109+
110+
// Assign a NONDET expression to the temporary symbol
111+
symbol_exprt temp_return_symbol(symbol_ptr->name, return_type);
112+
exprt return_symbol_expr=side_effect_expr_nondett(return_type);
113+
code_declt temp_return_decl(temp_return_symbol);
114+
temp_return_decl.copy_to_operands(return_symbol_expr);
115+
116+
// Add the temporary symbol declaration and the return expression
117+
// to the body for the stubbed function
118+
new_instructions.copy_to_operands(temp_return_decl);
119+
new_instructions.copy_to_operands(code_returnt(temp_return_symbol));
120+
symbol.value=new_instructions;
121+
return symbol_ptr->name;
122+
}
123+
124+
return ID_nil;
125+
}
126+
127+
/*******************************************************************\
128+
129+
Function: ansi_c_languaget::build_stub_parameter_symbol
130+
131+
Inputs:
132+
function_symbol - the symbol of an opaque function
133+
parameter_index - the index of the parameter within the
134+
the parameter list
135+
parameter_type - the type of the parameter
136+
137+
Outputs: A named symbol to be added to the symbol table representing
138+
one of the parameters in this opaque function.
139+
140+
Purpose: To build the parameter symbol and choose its name. For C
141+
we do not have to worry about this pointers so can just
142+
name the parameters according to index.
143+
Builds a parameter with name stub_ignored_arg0,...
144+
145+
\*******************************************************************/
146+
147+
parameter_symbolt ansi_c_languaget::build_stub_parameter_symbol(
148+
const symbolt &function_symbol,
149+
size_t parameter_index,
150+
const code_typet::parametert &parameter)
151+
{
152+
irep_idt base_name="stub_ignored_arg"+i2string(parameter_index);
153+
irep_idt identifier=id2string(function_symbol.name)+"::"+id2string(base_name);
154+
155+
parameter_symbolt parameter_symbol;
156+
parameter_symbol.base_name=base_name;
157+
parameter_symbol.mode=ID_C;
158+
parameter_symbol.name=identifier;
159+
parameter_symbol.type=parameter.type();
160+
161+
return parameter_symbol;
162+
}
163+
164+
/*******************************************************************\
165+
68166
Function: ansi_c_languaget::preprocess
69167
70168
Inputs:
@@ -194,6 +292,8 @@ Function: ansi_c_languaget::final
194292

195293
bool ansi_c_languaget::final(symbol_tablet &symbol_table)
196294
{
295+
generate_opaque_method_stubs(symbol_table);
296+
197297
if(ansi_c_entry_point(symbol_table, "main", get_message_handler()))
198298
return true;
199299

src/ansi-c/ansi_c_language.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ Author: Daniel Kroening, [email protected]
1515

1616
#include "ansi_c_parse_tree.h"
1717

18+
class symbolt;
19+
class symbol_tablet;
20+
1821
/*! \brief TO_BE_DOCUMENTED
1922
\ingroup gr_ansi_c
2023
*/
@@ -73,6 +76,15 @@ class ansi_c_languaget:public languaget
7376
void modules_provided(std::set<std::string> &modules) override;
7477

7578
protected:
79+
virtual irep_idt generate_opaque_stub_body(
80+
symbolt &symbol,
81+
symbol_tablet &symbol_table) override;
82+
83+
virtual parameter_symbolt build_stub_parameter_symbol(
84+
const symbolt &function_symbol,
85+
size_t parameter_index,
86+
const code_typet::parametert &parameter) override;
87+
7688
ansi_c_parse_treet parse_tree;
7789
std::string parse_path;
7890
};

src/util/language.cpp

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ Author: Daniel Kroening, [email protected]
88

99
#include "language.h"
1010
#include "expr.h"
11+
#include <util/symbol.h>
12+
#include <util/symbol_table.h>
13+
#include <util/prefix.h>
14+
#include <util/cprover_prefix.h>
15+
#include <util/std_types.h>
1116

1217
/*******************************************************************\
1318
@@ -125,3 +130,183 @@ bool languaget::type_to_name(
125130
name=type.pretty();
126131
return false;
127132
}
133+
134+
/*******************************************************************\
135+
136+
Function: languaget::generate_opaque_method_stubs
137+
138+
Inputs:
139+
symbol_table - the symbol table for the program
140+
141+
Outputs:
142+
143+
Purpose: When there are opaque methods (e.g. ones where we don't
144+
have a body), we create a stub function in the goto
145+
program and mark it as opaque so the interpreter fills in
146+
appropriate values for it.
147+
148+
\*******************************************************************/
149+
150+
void languaget::generate_opaque_method_stubs(symbol_tablet &symbol_table)
151+
{
152+
for(auto &symbol_entry : symbol_table.symbols)
153+
{
154+
if(is_symbol_opaque_function(symbol_entry.second))
155+
{
156+
symbolt &symbol=symbol_entry.second;
157+
158+
generate_opaque_parameter_symbols(symbol, symbol_table);
159+
160+
irep_idt return_symbol_id = generate_opaque_stub_body(
161+
symbol,
162+
symbol_table);
163+
164+
if(return_symbol_id!=ID_nil)
165+
{
166+
symbol.type.set("opaque_method_capture_symbol", return_symbol_id);
167+
}
168+
}
169+
}
170+
}
171+
172+
/*******************************************************************\
173+
174+
Function: languaget::generate_opaque_stub_body
175+
176+
Inputs:
177+
symbol - the function symbol which is opaque
178+
symbol_table - the symbol table
179+
180+
Outputs: The identifier of the return variable. ID_nil if the function
181+
doesn't return anything.
182+
183+
Purpose: To generate the stub function for the opaque function in
184+
question. The identifier is used in the flag to the interpreter
185+
that the function is opaque. This function should be implemented
186+
in the languages.
187+
188+
\*******************************************************************/
189+
190+
irep_idt languaget::generate_opaque_stub_body(
191+
symbolt &symbol,
192+
symbol_tablet &symbol_table)
193+
{
194+
return ID_nil;
195+
}
196+
197+
/*******************************************************************\
198+
199+
Function: languaget::build_stub_parameter_symbol
200+
201+
Inputs:
202+
function_symbol - the symbol of an opaque function
203+
parameter_index - the index of the parameter within the
204+
the parameter list
205+
parameter_type - the type of the parameter
206+
207+
Outputs: A named symbol to be added to the symbol table representing
208+
one of the parameters in this opaque function.
209+
210+
Purpose: To build the parameter symbol and choose its name. This should
211+
be implemented in each language.
212+
213+
\*******************************************************************/
214+
215+
parameter_symbolt languaget::build_stub_parameter_symbol(
216+
const symbolt &function_symbol,
217+
size_t parameter_index,
218+
const code_typet::parametert &parameter)
219+
{
220+
error() << "language " << id()
221+
<< " doesn't implement build_stub_parameter_symbol. "
222+
<< "This means cannot use opaque functions." << eom;
223+
224+
return parameter_symbolt();
225+
}
226+
227+
/*******************************************************************\
228+
229+
Function: languaget::get_stub_return_symbol_name
230+
231+
Inputs:
232+
function_id - the function that has a return value
233+
234+
Outputs: the identifier to use for the symbol that will store the
235+
return value of this function.
236+
237+
Purpose: To get the name of the symbol to be used for the return value
238+
of the function. Generates a name like to_return_function_name
239+
240+
\*******************************************************************/
241+
242+
irep_idt languaget::get_stub_return_symbol_name(const irep_idt &function_id)
243+
{
244+
std::ostringstream return_symbol_name_builder;
245+
return_symbol_name_builder << "to_return_" << function_id;
246+
return return_symbol_name_builder.str();
247+
}
248+
249+
250+
/*******************************************************************\
251+
252+
Function: languaget::is_symbol_opaque_function
253+
254+
Inputs:
255+
symbol - the symbol to be checked
256+
257+
Outputs: True if the symbol is an opaque (e.g. non-bodied) function
258+
259+
Purpose: To identify if a given symbol is an opaque function and
260+
hence needs to be stubbed. We explicitly exclude CPROVER
261+
functions, if they have no body it is because we haven't
262+
generated it yet.
263+
264+
\*******************************************************************/
265+
266+
bool languaget::is_symbol_opaque_function(const symbolt &symbol)
267+
{
268+
// Explictly exclude CPROVER functions since these aren't opaque
269+
std::string variable_id_str(symbol.name.c_str());
270+
bool is_cprover_function = has_prefix(variable_id_str, CPROVER_PREFIX);
271+
272+
return !symbol.is_type &&
273+
symbol.value.id()==ID_nil &&
274+
symbol.type.id()==ID_code &&
275+
!is_cprover_function;
276+
}
277+
278+
/*******************************************************************\
279+
280+
Function: languaget::generate_opaque_parameter_symbols
281+
282+
Inputs:
283+
function_symbol - the symbol of an opaque function
284+
symbol_table - the symbol table to add the new parameter
285+
symbols into
286+
287+
Outputs:
288+
289+
Purpose: To create stub parameter symbols for each parameter the
290+
function has and assign their IDs into the parameters
291+
identifier.
292+
293+
\*******************************************************************/
294+
295+
void languaget::generate_opaque_parameter_symbols(
296+
symbolt &function_symbol,
297+
symbol_tablet &symbol_table)
298+
{
299+
code_typet &function_type = to_code_type(function_symbol.type);
300+
code_typet::parameterst &parameters=function_type.parameters();
301+
for(std::size_t i=0; i<parameters.size(); ++i)
302+
{
303+
code_typet::parametert &param=parameters[i];
304+
const parameter_symbolt &param_symbol=
305+
build_stub_parameter_symbol(function_symbol, i, param);
306+
307+
param.set_base_name(param_symbol.base_name);
308+
param.set_identifier(param_symbol.name);
309+
310+
symbol_table.add(param_symbol);
311+
}
312+
}

src/util/language.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Author: Daniel Kroening, [email protected]
1212
#include <set>
1313
#include <iosfwd>
1414
#include <string>
15+
#include <util/symbol.h>
16+
#include <util/std_types.h>
1517

1618
#include "message.h"
1719

@@ -101,5 +103,24 @@ class languaget:public messaget
101103

102104
languaget() { }
103105
virtual ~languaget() { }
106+
107+
protected:
108+
void generate_opaque_method_stubs(symbol_tablet &symbol_table);
109+
virtual irep_idt generate_opaque_stub_body(
110+
symbolt &symbol,
111+
symbol_tablet &symbol_table);
112+
113+
virtual parameter_symbolt build_stub_parameter_symbol(
114+
const symbolt &function_symbol,
115+
size_t parameter_index,
116+
const code_typet::parametert &parameter);
117+
118+
static irep_idt get_stub_return_symbol_name(const irep_idt &function_id);
119+
120+
private:
121+
bool is_symbol_opaque_function(const symbolt &symbol);
122+
void generate_opaque_parameter_symbols(
123+
symbolt &function_symbol,
124+
symbol_tablet &symbol_table);
104125
};
105126
#endif // CPROVER_UTIL_LANGUAGE_H

0 commit comments

Comments
 (0)