Fix spinlock race condition (rwlock)#560
Conversation
Readers try to acquire the lock using `fetch_add(2)` (least significant bit is reserved for the writers) and they check if a writer exists after they perform the addition. If there is a writer they undo their change using `fetch_sub(2)` . However if the writer unlocks before the `fetch_sub(2)` of the reader, setting the state to `UNLOCKED = 0`, then the subsequent `fetch_sub` of the reader ends up corrupting the state, overflowing and wrapping around. With this change the `unlock_exclusive` just clears the writer bit from the state, leaving the reader counts unchanged. The caller must hold the lock so the state must have the writer bit set prior.
|
I went back to this to see how the loom tests did not catch this. I realized that I just changed the order, writer is in the main thread, reader is spawn. This way it requires one less preemption to hit the bug. |
|
Good catch, thanks for fixing this! Re:
I think adding a new test where the writer is in the main thread seems like a good approach --- it's unfortunate that the ordering impacts whether or not the test catches the bug, but I think increasing the global preemption bound on CI will make some of the other Another option might be to use |
Readers try to acquire the lock using
fetch_add(2)(least significant bit is reserved for the writers) and they check if a writer exists after they perform the addition. If there is a writer they undo their change usingfetch_sub(2). However if the writer unlocks before thefetch_sub(2)of the reader, setting the state toUNLOCKED = 0, then the subsequentfetch_subof the reader ends up corrupting the state, overflowing and wrapping around.With this change the
unlock_exclusivejust clears the writer bit from the state, leaving the reader counts unchanged. The caller must hold the lock so the state must have the writer bit set prior.