Skip to content

Commit a382218

Browse files
committed
L1 renaming at each declaration
This was done up until c8f0f7b. The (observable) problem tackled here is that objects declared in loops got the same L1 name, which implies they had the same address. Thus objects were spuriously reported as dead when their address was taken, because a pointer to the latest (live) object would be the same as one to an earlier (genuinely dead) object. A side effect of this change is objects generated for test suites now have L1 indices, as witnessed in the pointer-function-parameters test.
1 parent 16cc469 commit a382218

File tree

11 files changed

+93
-72
lines changed

11 files changed

+93
-72
lines changed

regression/cbmc-cover/pointer-function-parameters/test.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ main.c
44
^\*\* 5 of 5 covered \(100\.0%\)$
55
^Test suite:$
66
^(tmp(\$\d+)?=[^,]*, a=\(\(signed int \*\)NULL\))|(a=\(\(signed int \*\)NULL\), tmp(\$\d+)?=[^,]*)$
7-
^(a=&tmp(\$\d+)?!0, tmp(\$\d+)?=4)|(tmp(\$\d+)?=4, a=&tmp(\$\d+)?!0)$
8-
^(a=&tmp(\$\d+)?!0, tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+))|(tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+), a=&tmp(\$\d+)?!0)$
7+
^(a=&tmp(\$\d+)?!0@1, tmp(\$\d+)?=4)|(tmp(\$\d+)?=4, a=&tmp(\$\d+)?!0@1)$
8+
^(a=&tmp(\$\d+)?!0@1, tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+))|(tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+), a=&tmp(\$\d+)?!0@1)$
99
^EXIT=0$
1010
^SIGNAL=0$
1111
--
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
int g;
2+
3+
int main()
4+
{
5+
for(int i = 0; i < 4; ++i)
6+
{
7+
int *x;
8+
*&x = &g;
9+
}
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--pointer-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

regression/cbmc/vla3/test.desc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,4 @@ main.c
77
--
88
^warning: ignoring
99
--
10-
Renaming is inconsistent across loop iterations as we map L1 names to types, but
11-
do not actually introduce new L1 ids each time we declare an object.
10+
The array decision procedure does not yet handle member expressions.

src/goto-programs/goto_clean_expr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ symbol_exprt goto_convertt::make_compound_literal(
4545

4646
// The lifetime of compound literals is really that of
4747
// the block they are in.
48-
copy(code_declt(result), DECL, dest);
48+
if(!new_symbol.is_static_lifetime)
49+
copy(code_declt(result), DECL, dest);
4950

5051
code_assignt code_assign(result, expr);
5152
code_assign.add_source_location()=source_location;

src/goto-symex/goto_symex_state.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,3 +796,29 @@ void goto_statet::output_propagation_map(std::ostream &out)
796796
out << name_value.first << " <- " << format(name_value.second) << "\n";
797797
}
798798
}
799+
800+
void goto_symex_statet::add_object(
801+
ssa_exprt &ssa,
802+
std::size_t l1_index,
803+
const namespacet &ns)
804+
{
805+
framet &frame = top();
806+
807+
const irep_idt l0_name = ssa.get_identifier();
808+
809+
// save old L1 name, if any
810+
auto existing_or_new_entry = level1.current_names.emplace(
811+
std::piecewise_construct,
812+
std::forward_as_tuple(l0_name),
813+
std::forward_as_tuple(ssa, l1_index));
814+
815+
if(!existing_or_new_entry.second)
816+
{
817+
frame.old_level1.emplace(l0_name, existing_or_new_entry.first->second);
818+
existing_or_new_entry.first->second = std::make_pair(ssa, l1_index);
819+
}
820+
821+
ssa = rename_ssa<L1>(std::move(ssa), ns);
822+
const bool inserted = frame.local_objects.insert(ssa.get_identifier()).second;
823+
INVARIANT(inserted, "l1_name expected to be unique by construction");
824+
}

src/goto-symex/goto_symex_state.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,6 @@ class goto_symex_statet final : public goto_statet
144144

145145
symex_target_equationt *symex_target;
146146

147-
// we remember all L1 renamings
148-
std::set<irep_idt> l1_history;
149-
150147
symex_level0t level0;
151148
symex_level1t level1;
152149

@@ -257,6 +254,10 @@ class goto_symex_statet final : public goto_statet
257254

258255
const framet &previous_frame() { return *(--(--call_stack().end())); }
259256

257+
/// Turn L0-renamed \p ssa into an L1-renamed SSA expression with an L1 index
258+
/// \p l1_index that must not have previously been used.
259+
void add_object(ssa_exprt &ssa, std::size_t l1_index, const namespacet &ns);
260+
260261
void print_backtrace(std::ostream &) const;
261262

262263
// threads

src/goto-symex/path_storage.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,24 @@ class path_storaget
9898
/// error-handling paths.
9999
std::unordered_map<irep_idt, local_safe_pointerst> safe_pointers;
100100

101+
/// Provide a unique index for a given \p id, starting from \p minimum_index.
102+
std::size_t get_unique_index(const irep_idt &id, std::size_t minimum_index)
103+
{
104+
auto entry = unique_index_map.emplace(id, minimum_index);
105+
106+
if(!entry.second)
107+
entry.first->second = std::max(entry.first->second + 1, minimum_index);
108+
109+
return entry.first->second;
110+
}
111+
101112
private:
102113
// Derived classes should override these methods, allowing the base class to
103114
// enforce preconditions.
104115
virtual patht &private_peek() = 0;
105116
virtual void private_pop() = 0;
117+
118+
std::unordered_map<irep_idt, std::size_t> unique_index_map;
106119
};
107120

108121
/// \brief LIFO save queue: depth-first search, try to finish paths

src/goto-symex/symex_decl.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,16 @@ void goto_symext::symex_decl(statet &state)
3434

3535
void goto_symext::symex_decl(statet &state, const symbol_exprt &expr)
3636
{
37-
// We increase the L2 renaming to make these non-deterministic.
38-
// We also prevent propagation of old values.
39-
40-
ssa_exprt ssa = state.rename_ssa<L1>(ssa_exprt{expr}, ns);
37+
// each declaration introduces a new object, which we record as a fresh L1
38+
// index
39+
40+
ssa_exprt ssa = state.rename_ssa<L0>(ssa_exprt{expr}, ns);
41+
// We use "1" as the first level-1 index, which is in line with doing so for
42+
// level-2 indices (but it's an arbitrary choice, we have just always been
43+
// doing it this way).
44+
const std::size_t fresh_l1_index =
45+
path_storage.get_unique_index(ssa.get_identifier(), 1);
46+
state.add_object(ssa, fresh_l1_index, ns);
4147
const irep_idt &l1_identifier = ssa.get_identifier();
4248

4349
// rename type to L2
@@ -57,16 +63,11 @@ void goto_symext::symex_decl(statet &state, const symbol_exprt &expr)
5763
state.value_set.assign(ssa, l1_rhs, ns, true, false);
5864
}
5965

60-
// prevent propagation
61-
state.propagation.erase(l1_identifier);
62-
6366
// L2 renaming
64-
// inlining may yield multiple declarations of the same identifier
65-
// within the same L1 context
66-
const auto level2_it =
67-
state.level2.current_names.emplace(l1_identifier, std::make_pair(ssa, 0))
68-
.first;
69-
symex_renaming_levelt::increase_counter(level2_it);
67+
bool is_new =
68+
state.level2.current_names.emplace(l1_identifier, std::make_pair(ssa, 1))
69+
.second;
70+
CHECK_RETURN(is_new);
7071
const bool record_events=state.record_events;
7172
state.record_events=false;
7273
exprt expr_l2 = state.rename(std::move(ssa), ns);

src/goto-symex/symex_function_call.cpp

Lines changed: 10 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Author: Daniel Kroening, [email protected]
2222
static void locality(
2323
const irep_idt &function_identifier,
2424
goto_symext::statet &state,
25+
path_storaget &path_storage,
2526
const goto_functionst::goto_functiont &goto_function,
2627
const namespacet &ns);
2728

@@ -305,7 +306,7 @@ void goto_symext::symex_function_call_code(
305306
framet &frame = state.new_frame();
306307

307308
// preserve locality of local variables
308-
locality(identifier, state, goto_function, ns);
309+
locality(identifier, state, path_storage, goto_function, ns);
309310

310311
// assign actuals to formal parameters
311312
parameter_assignments(identifier, goto_function, state, arguments);
@@ -381,68 +382,27 @@ void goto_symext::symex_end_of_function(statet &state)
381382
pop_frame(state);
382383
}
383384

384-
/// preserves locality of local variables of a given function by applying L1
385-
/// renaming to the local identifiers
385+
/// Preserves locality of parameters of a given function by applying L1
386+
/// renaming to them.
386387
static void locality(
387388
const irep_idt &function_identifier,
388389
goto_symext::statet &state,
390+
path_storaget &path_storage,
389391
const goto_functionst::goto_functiont &goto_function,
390392
const namespacet &ns)
391393
{
392394
unsigned &frame_nr=
393395
state.threads[state.source.thread_nr].function_frame[function_identifier];
394396
frame_nr++;
395397

396-
std::set<irep_idt> local_identifiers;
397-
398-
get_local_identifiers(goto_function, local_identifiers);
399-
400-
framet &frame = state.top();
401-
402-
for(std::set<irep_idt>::const_iterator
403-
it=local_identifiers.begin();
404-
it!=local_identifiers.end();
405-
it++)
398+
for(const auto &param : goto_function.parameter_identifiers)
406399
{
407400
// get L0 name
408401
ssa_exprt ssa =
409-
state.rename_ssa<L0>(ssa_exprt{ns.lookup(*it).symbol_expr()}, ns);
410-
const irep_idt l0_name=ssa.get_identifier();
411-
412-
// save old L1 name for popping the frame
413-
auto c_it = state.level1.current_names.find(l0_name);
414-
415-
if(c_it != state.level1.current_names.end())
416-
{
417-
frame.old_level1.emplace(l0_name, c_it->second);
418-
c_it->second = std::make_pair(ssa, frame_nr);
419-
}
420-
else
421-
{
422-
c_it = state.level1.current_names
423-
.emplace(l0_name, std::make_pair(ssa, frame_nr))
424-
.first;
425-
}
426-
427-
// do L1 renaming -- these need not be unique, as
428-
// identifiers may be shared among functions
429-
// (e.g., due to inlining or other code restructuring)
430-
431-
ssa_exprt ssa_l1 = state.rename_ssa<L1>(std::move(ssa), ns);
432-
433-
irep_idt l1_name = ssa_l1.get_identifier();
434-
unsigned offset=0;
435-
436-
while(state.l1_history.find(l1_name)!=state.l1_history.end())
437-
{
438-
symex_renaming_levelt::increase_counter(c_it);
439-
++offset;
440-
ssa_l1.set_level_1(frame_nr + offset);
441-
l1_name = ssa_l1.get_identifier();
442-
}
402+
state.rename_ssa<L0>(ssa_exprt{ns.lookup(param).symbol_expr()}, ns);
443403

444-
// now unique -- store
445-
frame.local_objects.insert(l1_name);
446-
state.l1_history.insert(l1_name);
404+
const std::size_t fresh_l1_index =
405+
path_storage.get_unique_index(ssa.get_identifier(), frame_nr);
406+
state.add_object(ssa, fresh_l1_index, ns);
447407
}
448408
}

src/goto-symex/symex_start_thread.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ void goto_symext::symex_start_thread(statet &state)
6666

6767
// get L0 name for current thread
6868
lhs.set_level_0(t);
69+
const irep_idt &l0_name = lhs.get_identifier();
70+
std::size_t l1_index = path_storage.get_unique_index(l0_name, 0);
71+
CHECK_RETURN(l1_index == 0);
6972

7073
// set up L1 name
7174
auto emplace_result = state.level1.current_names.emplace(
@@ -76,7 +79,6 @@ void goto_symext::symex_start_thread(statet &state)
7679
const ssa_exprt lhs_l1 = state.rename_ssa<L1>(std::move(lhs), ns);
7780
const irep_idt l1_name = lhs_l1.get_l1_object_identifier();
7881
// store it
79-
state.l1_history.insert(l1_name);
8082
new_thread.call_stack.back().local_objects.insert(l1_name);
8183

8284
// make copy

0 commit comments

Comments
 (0)