File tree Expand file tree Collapse file tree 1 file changed +20
-11
lines changed
Expand file tree Collapse file tree 1 file changed +20
-11
lines changed Original file line number Diff line number Diff line change @@ -673,18 +673,27 @@ POOL_(acquire)( POOL_(t) * join,
673673
674674 ulong ele_nxt = POOL_ (private_idx )( ele0 [ ele_idx ].POOL_NEXT );
675675
676- if ( FD_UNLIKELY ( (ele_nxt >=ele_max ) & (!POOL_ (idx_is_null )( ele_nxt )) ) ) { /* opt for not corrupt */
677- err = FD_POOL_ERR_CORRUPT ;
678- break ;
679- }
680-
681- ulong new_ver_top = POOL_ (private_vidx )( ver + 2UL , ele_nxt );
682-
683- if ( FD_LIKELY ( POOL_ (private_cas )( _v , ver_top , new_ver_top )== ver_top ) ) { /* opt for low contention */
684- ele = ele0 + ele_idx ;
685- break ;
676+ if ( FD_UNLIKELY ( (ele_nxt >=ele_max ) & (!POOL_ (idx_is_null )( ele_nxt )) ) ) { /* ele_nxt is invalid, opt for valid */
677+ /* It is possible that another thread acquired ele_idx and
678+ repurposed ele_idx's POOL_NEXT (storing something in it that
679+ isn't a valid pool value) between when we read ver_top and
680+ when we read ele_idx's POOL_NEXT above. If so, the pool
681+ version would be changed from what we read above. We thus
682+ only signal ERR_CORRUPT if the version number hasn't changed
683+ since we read it. */
684+
685+ if ( FD_UNLIKELY ( POOL_ (private_vidx_ver )( * _v )== ver ) ) {
686+ err = FD_POOL_ERR_CORRUPT ;
687+ break ;
688+ }
689+ } else { /* ele_nxt is valid */
690+ ulong new_ver_top = POOL_ (private_vidx )( ver + 2UL , ele_nxt );
691+
692+ if ( FD_LIKELY ( POOL_ (private_cas )( _v , ver_top , new_ver_top )== ver_top ) ) { /* opt for low contention */
693+ ele = ele0 + ele_idx ;
694+ break ;
695+ }
686696 }
687-
688697 } else if ( FD_UNLIKELY ( !blocking ) ) { /* opt for blocking */
689698
690699 err = FD_POOL_ERR_AGAIN ;
You can’t perform that action at this time.
0 commit comments