[SERVER-42370] Race between SharedStateImpl::addChild and transitionToFinished Created: 23/Jul/19  Updated: 29/Oct/23  Resolved: 24/Jul/19

Status: Closed
Project: Core Server
Component/s: Internal Code
Affects Version/s: None
Fix Version/s: 4.2.0-rc5, 4.3.1

Type: Bug Priority: Major - P3
Reporter: Mira Carey Assignee: Mira Carey
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Backports
Depends
Backwards Compatibility: Fully Compatible
Operating System: ALL
Backport Requested:
v4.2
Sprint: Service Arch 2019-08-12
Participants:
Linked BF Score: 10

 Description   

There's an unfortunate race between addChild and transitionToFinished, where the caller of addChild can observe a kInit shared state, as can transitionToFinished, and then the caller of addChild can add a child that is never fulfilled by the caller of transitionToFinished.

It looks like:

addChild() transitionToFinished()
loadState, observe init  
acquire mutex  
loadState, observe init  
  transition to finished, observed init
attempt to cas to waitingOrHaveChildren  
  return, doing nothing
add to children  
strand the child in a way that won't be finished later  


 Comments   
Comment by Githook User [ 24/Jul/19 ]

Author:

{'name': 'Jason Carey', 'email': 'jcarey@argv.me', 'username': 'hanumantmk'}

Message: SERVER-42370 Fix SharedStateImpl::addChild()

There's an unfortunate race between addChild and transitionToFinished,
where the caller of addChild can observe a kInit shared state, as can
transitionToFinished, and then the caller of addChild can add a child
that is never fulfilled by the caller of transitionToFinished.

It looks like:

addChild() | transitionToFinished()
==============================================
loadState, see init |
acquire mutex |
loadState, see init |

transition to finished, observed init
attempt to cas, fail
return, doing nothing
add to children

strand the child |

The fix is to check to see if our compare_exchange failed, in which case
we need to fulfill ourselves

(cherry picked from commit e82c7b495f4c4cebf12f4f1a19c2922b1d1d2683)
Branch: v4.2
https://github.com/mongodb/mongo/commit/aa5fef386e734d42ad8df1d0d37021daf38fc56c

Comment by Githook User [ 24/Jul/19 ]

Author:

{'name': 'Jason Carey', 'email': 'jcarey@argv.me', 'username': 'hanumantmk'}

Message: SERVER-42370 Fix SharedStateImpl::addChild()

There's an unfortunate race between addChild and transitionToFinished,
where the caller of addChild can observe a kInit shared state, as can
transitionToFinished, and then the caller of addChild can add a child
that is never fulfilled by the caller of transitionToFinished.

It looks like:

addChild() | transitionToFinished()
==============================================
loadState, see init |
acquire mutex |
loadState, see init |

transition to finished, observed init
attempt to cas, fail
return, doing nothing
add to children

strand the child |

The fix is to check to see if our compare_exchange failed, in which case
we need to fulfill ourselves
Branch: master
https://github.com/mongodb/mongo/commit/e82c7b495f4c4cebf12f4f1a19c2922b1d1d2683

Generated at Thu Feb 08 05:00:19 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.