Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Fix atomicity violation in network-devp2p #11277

Merged
merged 1 commit into from Dec 10, 2019
Merged

Fix atomicity violation in network-devp2p #11277

merged 1 commit into from Dec 10, 2019

Conversation

BurtonQin
Copy link
Contributor

It is to fix an atomicity violation in network-devp2p.

https://github.com/paritytech/parity-ethereum/blob/ee016127686f6cc63815b15d7df5aa22f4edc22c/util/network-devp2p/src/connection.rs#L222-L232

Following the same bug pattern of #5910
In function register_socket:

  1. atomic variable registered is loaded and checked
  2. if it is true, directly returns
  3. otherwise, execute some code and set the atomic variable to true.

It seems that the atomic variable is used to guarantee that the inner code will only be executed once in multiple calls.
The function takes &self (instead of &mut self) and I think it may be called in different threads simultaneously.
If that is the case, the following execution path may happen:

  1. Thread1 calls load and check, gets false
  2. Thread2 calls load and check, also gets false
  3. Thread2 calls the inner code and sets the variable to true
  4. Thread1 calls the inner code again.

The atomicity violation happens because the read and write of one atomic variable are interleaved by another write.

The fix is to use one compare_and_swap to replace the separate load and store, as shown in the fix.
✄ -----------------------------------------------------------------------------

@parity-cla-bot
Copy link

It looks like @BurtonQin signed our Contributor License Agreement. 👍

Many thanks,

Parity Technologies CLA Bot

@@ -220,14 +220,13 @@ impl Connection {

/// Register this connection with the IO event loop.
pub fn register_socket<Host: Handler>(&self, reg: Token, event_loop: &mut EventLoop<Host>) -> io::Result<()> {
if self.registered.load(AtomicOrdering::SeqCst) {
if self.registered.compare_and_swap(false, true, AtomicOrdering::SeqCst) {
return Ok(());
}
trace!(target: "network", "connection register; token={:?}", reg);
if let Err(e) = event_loop.register(&self.socket, reg, self.interest, PollOpt::edge() /* | PollOpt::oneshot() */) { // TODO: oneshot is broken on windows
trace!(target: "network", "Failed to register {:?}, {:?}", reg, e);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why we don't return here (and set self.registered back to false).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arkpar I'll go ahead and merge this now, but I'm still curious. :)

@dvdplm dvdplm added A8-looksgood 🦄 Pull request is reviewed well. B0-patch-stable 🕷 Pull request should also be back-ported to the stable branch. B1-patch-beta 🕷🕷 M4-io 💾 Interaction with filesystem/databases. labels Dec 10, 2019
@dvdplm dvdplm merged commit f1f6493 into openethereum:master Dec 10, 2019
dvdplm added a commit that referenced this pull request Dec 15, 2019
…ate their data instead

Merge branch 'master' into dp/chore/kvdb-no-default-column

* master:
  tx-q: enable basic verification of local transactions (#11332)
  remove null signatures (#11335)
  ethcore/res: activate agharta on classic 9573000 (#11331)
  [secretstore] migrate to version 4 (#11322)
  Enable EIP-2384 for ice age hard fork (#11281)
  Fix atomicity violation in network-devp2p (#11277)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A8-looksgood 🦄 Pull request is reviewed well. B0-patch-stable 🕷 Pull request should also be back-ported to the stable branch. M4-io 💾 Interaction with filesystem/databases.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants