Skip to content

Commit aee96fc

Browse files
committed
Concurrency: treat updates to an unknown field as atomic
Writing to an object that is composed of multiple fields is generally treated in a field-sensitive (and thus: single-field) manner, which had fixed several issues in handling shared arrays or structs. When the specific field being updated cannot be determined during symbolic execution (as is the case with non-const indices into arrays), we update all fields that make up the full object. Such a full-object update must then be treated as an atomic operation to avoid losing intermittent writes performed by other threads. Fixes: diffblue#123
1 parent 352be59 commit aee96fc

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
int data[2];
2+
unsigned sync;
3+
4+
void thread()
5+
{
6+
data[sync % 2] = 1;
7+
__CPROVER_assert(data[sync % 2] == 1, "1");
8+
}
9+
10+
int main()
11+
{
12+
unsigned nondet;
13+
sync = nondet;
14+
__CPROVER_ASYNC_1:
15+
thread();
16+
unsigned sync_value = sync;
17+
data[(sync_value + 1) % 2] = 2;
18+
__CPROVER_assert(data[(sync_value + 1) % 2] == 2, "2");
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/goto-symex/goto_symex.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,27 @@ void goto_symext::symex_assign(
115115
return;
116116
}
117117

118+
// We may end up reading (and writing) all components of an object composed
119+
// of multiple fields. In such cases, we must do so atomically to avoid
120+
// overwriting components modified by another thread. Note that this also
121+
// implies multiple shared reads on the rhs being treated as atomic.
122+
const bool maybe_divisible =
123+
lhs.id() == ID_index ||
124+
(is_ssa_expr(lhs) &&
125+
state.field_sensitivity.is_divisible(to_ssa_expr(lhs)));
126+
const bool need_atomic_section = maybe_divisible &&
127+
state.threads.size() > 1 &&
128+
state.atomic_section_id == 0;
129+
130+
if(need_atomic_section)
131+
symex_atomic_begin(state);
132+
118133
exprt::operandst lhs_if_then_else_conditions;
119134
symex_assign.assign_rec(
120135
lhs, expr_skeletont{}, rhs, lhs_if_then_else_conditions);
136+
137+
if(need_atomic_section)
138+
symex_atomic_end(state);
121139
}
122140
}
123141

0 commit comments

Comments
 (0)