Skip to content

Commit 91f6c35

Browse files
committed
Dirty locals copied across threads require program-order constraints
We previously lacked SHARED_WRITE events in program order in a newly-spawned thread for dirty locals being copied from the spawning thread. This resulted in spurious failures as reading from initial values seemed possible, when the from-read constraint should have prevented such reads. Also, replace the variable "t" by the more descriptive "new_thread_nr."
1 parent c884836 commit 91f6c35

File tree

2 files changed

+23
-13
lines changed

2 files changed

+23
-13
lines changed
Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33
-Dlocals_bug
44
^EXIT=0$
@@ -7,12 +7,6 @@ main.c
77
--
88
^warning: ignoring
99
--
10-
There is a need for further debugging around copying local objects in
11-
the procedure spawning threads as we generate the following non-sensical
12-
constraint:
13-
// 28 file regression/cbmc-concurrency/dirty_local3/main.c line 3 function worker
14-
(57) CONSTRAINT(z!1@0#2 == z!1@0 || !choice_rf0)
15-
^^^^^^^^^^^^^^^^
16-
comparison of L2 and L1 SSA symbols
17-
// 28 file regression/cbmc-concurrency/dirty_local3/main.c line 3 function worker
18-
(58) CONSTRAINT(choice_rf0)
10+
We previously missed SHARED_WRITE events in program order in a newly-spawned
11+
thread for dirty locals, resulting in spurious failures as reading from initial
12+
values seemed possible.

src/goto-symex/symex_start_thread.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ void goto_symext::symex_start_thread(statet &state)
3939
instruction.get_target();
4040

4141
// put into thread vector
42-
std::size_t t=state.threads.size();
42+
const std::size_t new_thread_nr = state.threads.size();
4343
state.threads.push_back(statet::threadt(guard_manager));
4444
// statet::threadt &cur_thread=state.threads[state.source.thread_nr];
4545
statet::threadt &new_thread=state.threads.back();
@@ -53,6 +53,8 @@ void goto_symext::symex_start_thread(statet &state)
5353
new_thread.abstract_events=&(target.new_thread(cur_thread.abstract_events));
5454
#endif
5555

56+
const std::size_t current_thread_nr = state.source.thread_nr;
57+
5658
// create a copy of the local variables for the new thread
5759
framet &frame = state.call_stack().top();
5860

@@ -71,7 +73,8 @@ void goto_symext::symex_start_thread(statet &state)
7173
ssa_exprt lhs(pair.second.first.get_original_expr());
7274

7375
// get L0 name for current thread
74-
const renamedt<ssa_exprt, L0> l0_lhs = symex_level0(std::move(lhs), ns, t);
76+
const renamedt<ssa_exprt, L0> l0_lhs =
77+
symex_level0(std::move(lhs), ns, new_thread_nr);
7578
const irep_idt &l0_name = l0_lhs.get().get_identifier();
7679
std::size_t l1_index = path_storage.get_unique_l1_index(l0_name, 0);
7780
CHECK_RETURN(l1_index == 0);
@@ -92,7 +95,20 @@ void goto_symext::symex_start_thread(statet &state)
9295
symex_assignt{
9396
state, symex_targett::assignment_typet::HIDDEN, ns, symex_config, target}
9497
.assign_symbol(lhs_l1, expr_skeletont{}, rhs, lhs_conditions);
98+
const exprt l2_lhs = state.rename(lhs_l1, ns).get();
9599
state.record_events.pop();
100+
101+
// record a shared write in the new thread
102+
if(
103+
state.write_is_shared(lhs_l1, ns) ==
104+
goto_symex_statet::write_is_shared_resultt::SHARED &&
105+
is_ssa_expr(l2_lhs))
106+
{
107+
state.source.thread_nr = new_thread_nr;
108+
target.shared_write(
109+
state.guard.as_expr(), to_ssa_expr(l2_lhs), 0, state.source);
110+
state.source.thread_nr = current_thread_nr;
111+
}
96112
}
97113

98114
// initialize all variables marked thread-local
@@ -111,7 +127,7 @@ void goto_symext::symex_start_thread(statet &state)
111127
ssa_exprt lhs(symbol.symbol_expr());
112128

113129
// get L0 name for current thread
114-
lhs.set_level_0(t);
130+
lhs.set_level_0(new_thread_nr);
115131

116132
exprt rhs=symbol.value;
117133
if(rhs.is_nil())

0 commit comments

Comments
 (0)