Skip to content

Commit a397a58

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 365f246 commit a397a58

File tree

11 files changed

+95
-72
lines changed

11 files changed

+95
-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
@@ -766,3 +766,29 @@ void goto_symex_statet::print_backtrace(std::ostream &out) const
766766
<< frame.calling_location.pc->location_number << "\n";
767767
}
768768
}
769+
770+
void goto_symex_statet::add_object(
771+
ssa_exprt &ssa,
772+
std::size_t l1_index,
773+
const namespacet &ns)
774+
{
775+
framet &frame = call_stack().top();
776+
777+
const irep_idt l0_name = ssa.get_identifier();
778+
779+
// save old L1 name, if any
780+
auto existing_or_new_entry = level1.current_names.emplace(
781+
std::piecewise_construct,
782+
std::forward_as_tuple(l0_name),
783+
std::forward_as_tuple(ssa, l1_index));
784+
785+
if(!existing_or_new_entry.second)
786+
{
787+
frame.old_level1.emplace(l0_name, existing_or_new_entry.first->second);
788+
existing_or_new_entry.first->second = std::make_pair(ssa, l1_index);
789+
}
790+
791+
ssa = rename_ssa<L1>(std::move(ssa), ns);
792+
const bool inserted = frame.local_objects.insert(ssa.get_identifier()).second;
793+
INVARIANT(inserted, "l1_name expected to be unique by construction");
794+
}

src/goto-symex/goto_symex_state.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ class goto_symex_statet final : public goto_statet
6060

6161
symex_target_equationt *symex_target;
6262

63-
// we remember all L1 renamings
64-
std::set<irep_idt> l1_history;
65-
6663
symex_level0t level0;
6764
symex_level1t level1;
6865

@@ -141,6 +138,11 @@ class goto_symex_statet final : public goto_statet
141138
return threads[source.thread_nr].call_stack;
142139
}
143140

141+
/// Create a new instance of the L0-renamed object \p ssa. As part of this,
142+
/// turn \p ssa into an L1-renamed SSA expression. When doing so, use
143+
/// \p l1_index as the L1 index, which must not previously have been used.
144+
void add_object(ssa_exprt &ssa, std::size_t l1_index, const namespacet &ns);
145+
144146
void print_backtrace(std::ostream &) const;
145147

146148
// threads

src/goto-symex/path_storage.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,25 @@ 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+
/// Storage used by \ref get_unique_index.
119+
std::unordered_map<irep_idt, std::size_t> unique_index_map;
106120
};
107121

108122
/// \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

@@ -307,7 +308,7 @@ void goto_symext::symex_function_call_code(
307308
framet &frame = state.call_stack().new_frame(state.source);
308309

309310
// preserve locality of local variables
310-
locality(identifier, state, goto_function, ns);
311+
locality(identifier, state, path_storage, goto_function, ns);
311312

312313
// assign actuals to formal parameters
313314
parameter_assignments(identifier, goto_function, state, arguments);
@@ -383,68 +384,27 @@ void goto_symext::symex_end_of_function(statet &state)
383384
pop_frame(state);
384385
}
385386

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

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

446-
// now unique -- store
447-
frame.local_objects.insert(l1_name);
448-
state.l1_history.insert(l1_name);
406+
const std::size_t fresh_l1_index =
407+
path_storage.get_unique_index(ssa.get_identifier(), frame_nr);
408+
state.add_object(ssa, fresh_l1_index, ns);
449409
}
450410
}

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)