Skip to content

Commit 786f7d7

Browse files
authored
Merge pull request #5683 from tautschnig/atomic-section
Concurrency: ensure apply_condition's value is used
2 parents b90fc71 + 8a4fe6b commit 786f7d7

File tree

4 files changed

+106
-11
lines changed

4 files changed

+106
-11
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include <assert.h>
2+
3+
int start_main = 0;
4+
int mStartLock = 0;
5+
int __COUNT__ = 0;
6+
7+
void __VERIFIER_atomic_acquire()
8+
{
9+
__CPROVER_assume(mStartLock == 0);
10+
mStartLock = 1;
11+
}
12+
13+
void __VERIFIER_atomic_release()
14+
{
15+
__CPROVER_assume(mStartLock == 1);
16+
mStartLock = 0;
17+
}
18+
19+
void __VERIFIER_atomic_thr1()
20+
{
21+
if(__COUNT__ == 0)
22+
{
23+
__COUNT__ = __COUNT__ + 1;
24+
}
25+
else
26+
{
27+
assert(0);
28+
}
29+
}
30+
31+
void thr1()
32+
{
33+
__VERIFIER_atomic_acquire();
34+
start_main = 1;
35+
__VERIFIER_atomic_thr1();
36+
__VERIFIER_atomic_release();
37+
}
38+
39+
void __VERIFIER_atomic_thr2()
40+
{
41+
if(__COUNT__ == 1)
42+
{
43+
__COUNT__ = __COUNT__ + 1;
44+
}
45+
else
46+
{
47+
assert(0);
48+
}
49+
}
50+
51+
void thr2()
52+
{
53+
__CPROVER_assume(start_main != 0);
54+
__VERIFIER_atomic_acquire();
55+
__VERIFIER_atomic_release();
56+
__VERIFIER_atomic_thr2();
57+
}
58+
59+
int main()
60+
{
61+
__CPROVER_ASYNC_1:
62+
thr1();
63+
64+
thr2();
65+
66+
return 0;
67+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
KNOWNBUG
2+
main.c
3+
--program-only
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
__COUNT__#\d+ == (1 \+ __COUNT__#\d+|__COUNT__#\d+ \+ 1)
9+
--
10+
__COUNT__ is guaranteed to have been read within the atomic section, there
11+
should not be a need to produce a conditional assignment, and therefore the
12+
value of __COUNT__ can be constant propagated.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring

src/goto-symex/goto_symex_state.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,9 @@ bool goto_symex_statet::l2_thread_read_encoding(
395395
guardt g = guard_in_list;
396396
g-=guard;
397397
if(g.is_true())
398-
// there has already been a write to l1_identifier within
399-
// this atomic section under the same guard, or a guard
400-
// that implies the current one
398+
// There has already been a write to l1_identifier within this atomic
399+
// section under the same guard, or a guard implied by the current
400+
// one.
401401
return false;
402402

403403
write_guard |= guard_in_list;
@@ -417,9 +417,8 @@ bool goto_symex_statet::l2_thread_read_encoding(
417417
guardt g = a_s_read_guard; // copy
418418
g-=guard;
419419
if(g.is_true())
420-
// there has already been a read l1_identifier within
421-
// this atomic section under the same guard, or a guard
422-
// that implies the current one
420+
// There has already been a read of l1_identifier within this atomic
421+
// section under the same guard, or a guard implied by the current one.
423422
return false;
424423

425424
read_guard |= a_s_read_guard;
@@ -429,20 +428,29 @@ bool goto_symex_statet::l2_thread_read_encoding(
429428
if(!no_write.op().is_false())
430429
cond |= guardt{no_write.op(), guard_manager};
431430

432-
const renamedt<ssa_exprt, L2> l2_true_case = set_indices<L2>(ssa_l1, ns);
431+
// It is safe to perform constant propagation in case we have read or
432+
// written this object within the atomic section. We must actually do this,
433+
// because goto_state::apply_condition may have placed the latest value in
434+
// the propagation map without recording an assignment.
435+
auto p_it = propagation.find(ssa_l1.get_identifier());
436+
const exprt l2_true_case =
437+
p_it.has_value() ? *p_it : set_indices<L2>(ssa_l1, ns).get();
433438

434-
if(a_s_read.second.empty())
435-
{
439+
if(!cond.is_true())
436440
level2.increase_generation(l1_identifier, ssa_l1, fresh_l2_name_provider);
441+
442+
if(a_s_read.second.empty())
437443
a_s_read.first = level2.latest_index(l1_identifier);
438-
}
444+
439445
const renamedt<ssa_exprt, L2> l2_false_case = set_indices<L2>(ssa_l1, ns);
440446

441447
exprt tmp;
442448
if(cond.is_false())
443449
tmp = l2_false_case.get();
450+
else if(cond.is_true())
451+
tmp = l2_true_case;
444452
else
445-
tmp = if_exprt{cond.as_expr(), l2_true_case.get(), l2_false_case.get()};
453+
tmp = if_exprt{cond.as_expr(), l2_true_case, l2_false_case.get()};
446454

447455
record_events.push(false);
448456
ssa_exprt ssa_l2 = assignment(std::move(ssa_l1), tmp, ns, true, true).get();

0 commit comments

Comments
 (0)