Treiber: double free due to usage of compare_and_swap_raw
Created by: steffengy
Reproduction
let stack = Treiber::new();
stack.push(1);
stack.push(200);
stack.pop.unwrap();
::gc();
Analysis
stack.push(1)
works as expected.
During stack.push(200);
the following happens:
-
push(200)
callsself.head.compare_and_swap(...)
. -
compare_and_swap(...)
callscompare_and_swap_raw
which enques the old (1
) element asGarbage
stack.pop.unwrap()
also uses compare_and_swap
, which in this case
queues (=200)
as Garbage.
Then at the end, if you're running a sensitive allocator (such as a debug build on windows) it will crash due to a double free:
-
Garbage
::destroy frees the element for (=1), during the::gc
call. -
Treiber::drop
frees the head (=1) again (and the other items recursively, which doesn't happen here, since it crashes before) which leads to the crash.
Conclusion:
To me it seems, that Treiber needs a different compare_and_swap_raw
, which doesn't
enqueue the old elements as garbage, since they are still referenced after the swap.