@@ -24,16 +24,16 @@ private struct FlowControlState
2424 private const long AbortedBitMask = 1L << 32 ; // uint MaxValue + 1
2525 internal long _state ;
2626
27- public FlowControlState ( uint initialWindowSize , bool isAborted )
27+ public FlowControlState ( int size , bool isAborted )
2828 {
29- _state = initialWindowSize ;
29+ _state = ( uint ) size ; // Casted first to uint before assigning it to a long field to the address negative values
3030 if ( isAborted )
3131 {
3232 _state |= AbortedBitMask ;
3333 }
3434 }
3535
36- public uint Available => ( uint ) _state ;
36+ public int Available => ( int ) _state ;
3737
3838 public bool IsAborted => _state > uint . MaxValue ;
3939 }
@@ -49,19 +49,20 @@ public InputFlowControl(uint initialWindowSize, uint minWindowSizeIncrement)
4949 {
5050 Debug . Assert ( initialWindowSize >= minWindowSizeIncrement , "minWindowSizeIncrement is greater than the window size." ) ;
5151
52- _flow = new FlowControlState ( initialWindowSize , false ) ;
52+ _flow = new FlowControlState ( ( int ) initialWindowSize , isAborted : false ) ;
5353 _initialWindowSize = initialWindowSize ;
5454 _minWindowSizeIncrement = ( int ) minWindowSizeIncrement ;
5555 }
5656
5757 public bool IsAvailabilityLow => _flow . Available < _minWindowSizeIncrement ;
5858
59- // Test hook, not participating in mutual exclusion
60- internal uint Available => _flow . Available ;
59+ // Test hook
60+ internal int Available => _flow . Available ;
61+ internal bool IsAborted => _flow . IsAborted ;
6162
6263 public void Reset ( )
6364 {
64- _flow = new FlowControlState ( _initialWindowSize , false ) ;
65+ _flow = new FlowControlState ( ( int ) _initialWindowSize , isAborted : false ) ;
6566 _pendingUpdateSize = 0 ;
6667 _windowUpdatesDisabled = false ;
6768 }
@@ -72,6 +73,7 @@ public bool TryAdvance(int bytes)
7273 do
7374 {
7475 currentFlow = _flow ; // Copy
76+
7577 // Even if the stream is aborted, the client should never send more data than was available in the
7678 // flow-control window at the time of the abort.
7779 if ( bytes > currentFlow . Available )
@@ -84,7 +86,7 @@ public bool TryAdvance(int bytes)
8486 return false ;
8587 }
8688
87- computedFlow = new FlowControlState ( currentFlow . Available - ( uint ) bytes , isAborted : false ) ;
89+ computedFlow = new FlowControlState ( currentFlow . Available - bytes , isAborted : false ) ;
8890 } while ( currentFlow . _state != Interlocked . CompareExchange ( ref _flow . _state , computedFlow . _state , currentFlow . _state ) ) ;
8991
9092 return true ;
@@ -103,14 +105,12 @@ public bool TryUpdateWindow(int bytes, out int updateSize)
103105 return false ;
104106 }
105107
106- var maxUpdate = int . MaxValue - currentFlow . Available ;
107- if ( bytes > maxUpdate )
108- {
109- // We only try to update the window back to its initial size after the app consumes data.
110- // It shouldn't be possible for the window size to ever exceed Http2PeerSettings.MaxWindowSize.
111- Debug . Assert ( false , $ "{ nameof ( TryUpdateWindow ) } attempted to grow window past max size.") ;
112- }
113- computedFlow = new FlowControlState ( currentFlow . Available + ( uint ) bytes , isAborted : false ) ;
108+ var maxUpdate = Http2PeerSettings . MaxWindowSize - currentFlow . Available ;
109+
110+ // We only try to update the window back to its initial size after the app consumes data.
111+ // It shouldn't be possible for the window size to ever exceed Http2PeerSettings.MaxWindowSize.
112+ Debug . Assert ( bytes <= maxUpdate , $ "{ nameof ( TryUpdateWindow ) } attempted to grow window past max size.") ;
113+ computedFlow = new FlowControlState ( currentFlow . Available + bytes , isAborted : false ) ;
114114 } while ( currentFlow . _state != Interlocked . CompareExchange ( ref _flow . _state , computedFlow . _state , currentFlow . _state ) ) ;
115115
116116 if ( _windowUpdatesDisabled )
0 commit comments