Skip to content

Commit 023d0ce

Browse files
Merge pull request diffblue#407 from diffblue/bugfix/build_NONDET_retvals_replacements
SEC-387: Check assignment lhs matches function call return value
2 parents 9777364 + 6ef8922 commit 023d0ce

File tree

1 file changed

+65
-81
lines changed

1 file changed

+65
-81
lines changed

src/taint-analysis/taint_program.cpp

+65-81
Original file line numberDiff line numberDiff line change
@@ -12,98 +12,82 @@
1212
#include <analyses/call_graph_helpers.h>
1313
#include <unordered_set>
1414

15+
/// Remove assignment of non-dets to values if they can't be reached
16+
/// Mark instances of function call followed by assignment of non-det to
17+
/// function's return value
1518
static void build_NONDET_retvals_replacements(
1619
const goto_modelt &model,
1720
const namespacet &ns,
1821
replacements_of_NONDET_retvalst &replacements)
1922
{
2023
for(const auto &elem : model.goto_functions.function_map)
2124
{
22-
const auto & instructions=elem.second.body.instructions;
23-
auto instr_it=instructions.begin();
24-
if(instr_it==instructions.end())
25-
continue;
26-
for(auto next_instr_it=std::next(instr_it);
27-
next_instr_it!=instructions.end();
28-
instr_it = next_instr_it, ++next_instr_it)
25+
const goto_programt::instructionst &instructions =
26+
elem.second.body.instructions;
27+
for(auto instr_it = instructions.begin(); instr_it != instructions.end();
28+
++instr_it)
2929
{
30-
if(instr_it->type != FUNCTION_CALL || next_instr_it->type != ASSIGN)
30+
auto next_instr_it = std::next(instr_it);
31+
if(
32+
next_instr_it != instructions.end() &&
33+
instr_it->type == FUNCTION_CALL && next_instr_it->type == ASSIGN)
3134
{
32-
if(instr_it->type == ASSIGN)
33-
{
34-
const code_assignt &assign = to_code_assign(instr_it->code);
35-
if(assign.rhs().id() == ID_side_effect)
35+
const code_assignt &asgn = to_code_assign(next_instr_it->code);
36+
if(asgn.rhs().id() != ID_side_effect)
37+
continue;
38+
const side_effect_exprt see = to_side_effect_expr(asgn.rhs());
39+
if(see.get_statement() != ID_nondet)
40+
continue;
41+
42+
const code_function_callt &fn_call =
43+
to_code_function_call(instr_it->code);
44+
if(fn_call.function().id() != ID_symbol)
45+
continue;
46+
const irep_idt &callee_ident =
47+
to_symbol_expr(fn_call.function()).get_identifier();
48+
49+
std::string callee_return_value_symbol =
50+
id2string(callee_ident) + RETURN_VALUE_SUFFIX;
51+
if(!ns.get_symbol_table().has_symbol(callee_return_value_symbol))
52+
continue;
53+
54+
replacements.insert(
3655
{
37-
const side_effect_exprt side_effect =
38-
to_side_effect_expr(assign.rhs());
39-
if(side_effect.get_statement() == ID_nondet)
40-
{
41-
// See if we can see that this instruction is definitely
42-
// dead. Iterate backwards through the program from the current
43-
// instruction, looking for an unconditional GOTO or a target.
44-
// If we find an unconditional GOTO first then the instruction
45-
// is dead. If we find a target first then we must assume that
46-
// it can be reached. If we reach the beginning before finding
47-
// either then the instruction is reachable.
48-
bool is_dead = true;
49-
for(auto sit = instr_it;
50-
sit != instructions.begin();
51-
sit=std::prev(sit))
52-
{
53-
if(sit->is_target())
54-
{
55-
is_dead = false;
56-
break;
57-
}
58-
if(sit->type == GOTO && sit->guard.is_true())
59-
break;
60-
}
61-
if(is_dead || side_effect.type().id() == ID_pointer)
62-
{
63-
// Create a new static variable to put on the rhs of this
64-
// assignment. When the instruction is dead then this is
65-
// sound. Otherwise this is not sound, but it is
66-
// preferable to having a pointer that could point to
67-
// anything. A better solution would be to use the
68-
// replace_java_nondet pass or similar.
69-
static unsigned long counter = 0UL;
70-
std::stringstream sstr;
71-
sstr << "@__CPROVER_NONDET_dead_replace_" << ++counter;
72-
symbolt symbol;
73-
symbol.type =
74-
side_effect.type().id() == ID_pointer ?
75-
to_pointer_type(side_effect.type()).subtype() :
76-
side_effect.type();
77-
symbol.name = sstr.str();
78-
symbol.base_name = symbol.name;
79-
symbol.mode = ID_java;
80-
symbol.pretty_name = symbol.name;
81-
symbol.is_static_lifetime = true;
82-
const_cast<symbol_tablet&>(model.symbol_table).insert(symbol);
83-
replacements.insert({instr_it, symbol.symbol_expr()});
84-
}
85-
}
86-
}
87-
}
88-
continue;
56+
next_instr_it,
57+
ns.lookup(callee_return_value_symbol).symbol_expr()
58+
});
59+
}
60+
else if(instr_it->type == ASSIGN)
61+
{
62+
const code_assignt &assign = to_code_assign(instr_it->code);
63+
if(assign.rhs().id() != ID_side_effect)
64+
continue;
65+
const side_effect_exprt side_effect = to_side_effect_expr(assign.rhs());
66+
if(side_effect.get_statement() != ID_nondet)
67+
continue;
68+
if(side_effect.type().id() != ID_pointer)
69+
continue;
70+
// Create a new static variable to put on the rhs of this
71+
// assignment. When the instruction is dead then this is sound.
72+
// Otherwise this is not sound, but it is preferable to having a
73+
// pointer that could point to anything. A better solution would be
74+
// to use the convert_nondet pass or similar.
75+
static unsigned long counter = 0UL;
76+
std::stringstream sstr;
77+
sstr << "@__CPROVER_NONDET_dead_replace_" << ++counter;
78+
symbolt symbol;
79+
symbol.type =
80+
side_effect.type().id() == ID_pointer
81+
? to_pointer_type(side_effect.type()).subtype()
82+
: side_effect.type();
83+
symbol.name = sstr.str();
84+
symbol.base_name = symbol.name;
85+
symbol.mode = ID_java;
86+
symbol.pretty_name = symbol.name;
87+
symbol.is_static_lifetime = true;
88+
const_cast<symbol_tablet &>(model.symbol_table).insert(symbol);
89+
replacements.insert({ instr_it, symbol.symbol_expr() });
8990
}
90-
const code_function_callt &fn_call=to_code_function_call(instr_it->code);
91-
if(fn_call.function().id()!=ID_symbol)
92-
continue;
93-
const irep_idt &callee_ident=
94-
to_symbol_expr(fn_call.function()).get_identifier();
95-
96-
const code_assignt &asgn=to_code_assign(next_instr_it->code);
97-
if(asgn.rhs().id()!=ID_side_effect)
98-
continue;
99-
const side_effect_exprt see=to_side_effect_expr(asgn.rhs());
100-
if(see.get_statement()!=ID_nondet)
101-
continue;
102-
replacements.insert(
103-
{
104-
next_instr_it,
105-
ns.lookup(id2string(callee_ident) + RETURN_VALUE_SUFFIX).symbol_expr()
106-
});
10791
}
10892
}
10993
}

0 commit comments

Comments
 (0)