-
Notifications
You must be signed in to change notification settings - Fork 164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
reader.read() inside strategy.size() doesn't work #794
Comments
A related issue that makes me even more uncomfortable is that if you call |
Huh. I share your intuition that this should work. And also that it's code that should never be written. The full fix would be to do any necessary state checks immediately after calling size(). So I guess after step 4.b in ReadableStreamDefaultControllerEnqueue. Those checks would be... basically steps 2 and 3. (Also interesting: what if someone releases the reader lock? Seems to work OK.) I guess at a high level I see three choices:
I think we are currently going for (3). Although you could make an argument that handling exceptions thrown by size() at all, like we do now, is partially leaning toward (2). I think I am OK with that. It'd be improved a bit if I got around to fixing #427. We could also probably transition to (1) or (2) later if we really wanted, breaking only pathological code. |
We have the semantic that if a read() is in progress then size() isn't called at all. I was initially surprised by this, but it makes sense. However, it means that unlike WritableStream we can't just fix the reentrancy issue by hoisting the call to size() to before any other work is done. Meaning that there is unavoidable cost in overhead for fixing this. So I'm leaning towards (3), but I do worry that maybe the reason that no assert()s are tripping is because we don't have enough of them. There is a risk that implementations will track extra internal state that causes them violate their own invariants and crash here. I think I will add tests for the current behaviour so that hopefully such problems can be caught early. |
The 'pipeTo() inside size() should work' test didn't pass on Chromium's implementation as it performs the read() synchronously inside the call to pipeTo(). This encounters the race condition described in whatwg/streams#794. Although different from the reference implementation, What Chromium's implementation does here is valid and other implementations may do the same thing. As a workaround, queue a second chunk inside the test to trigger the first one to be read.
Chromium's implementation of pipeTo() is also affected, as it performs the first read synchronously. See web-platform-tests/wpt#8163. Although the reference implementation and Chromium are observably different here, I don't think either is wrong. |
Verify the results when calling ReadableStream and related class methods inside the size() function of the strategy. This results in user code being executed inside ReadableStreamDefaultControllerEnqueue, which can have surprising results. No real user code should be doing this, but it is important that implementations be robust in these cases. These tests are based closely on the ones in streams/transform-streams/reentrant-strategies.js, and are somewhat redundant with them. Since less code is under test here, these tests are easier to understand and debug. Additional tests cover getReader() and tee(). See whatwg/streams#794 for background of some of the stranger expectations here.
Verify the results when calling ReadableStream and related class methods inside the size() function of the strategy. This results in user code being executed inside ReadableStreamDefaultControllerEnqueue, which can have surprising results. No real user code should be doing this, but it is important that implementations be robust in these cases. These tests are based closely on the ones in streams/transform-streams/reentrant-strategies.js, and are somewhat redundant with them. Since less code is under test here, these tests are easier to understand and debug. Additional tests cover getReader() and tee(). See whatwg/streams#794 for background of some of the stranger expectations here.
I've written some ReadableStream tests at web-platform-tests/wpt#8166. I'm not sure I've covered every possible case where things can go wrong. As far as I can tell there is no way to call strategySize while already inside a call to strategySize, but I might have missed something. |
The 'pipeTo() inside size() should work' test didn't pass on Chromium's implementation as it performs the read() synchronously inside the call to pipeTo(). This encounters the race condition described in whatwg/streams#794. Although different from the reference implementation, What Chromium's implementation does here is valid and other implementations may do the same thing. As a workaround, queue a second chunk inside the test to trigger the first one to be read.
Verify the results when calling ReadableStream and related class methods inside the size() function of the strategy. This results in user code being executed inside ReadableStreamDefaultControllerEnqueue, which can have surprising results. No real user code should be doing this, but it is important that implementations be robust in these cases. These tests are based closely on the ones in streams/transform-streams/reentrant-strategies.js, and are somewhat redundant with them. Since less code is under test here, these tests are easier to understand and debug. Additional tests cover getReader() and tee(). See whatwg/streams#794 for background of some of the stranger expectations here.
I think we've decided to live with this rather than change it. Having said that, I will leave the issue open in case any implementers have problems with it. |
If I understand correctly, the following test should pass:
In practice it times out.
I think the reason is that at step 3 of ReadableStreamDefaultControllerEnqueue it decides that since there isn't a read in process, the chunk should be queued. Then when
read()
is called insidesize()
the chunk isn't queued yet, so the read is queued in ReadableStreamAddReadRequest and remains pending.Probably ReadableStreamDefaultControllerEnqueue should check ReadableStreamGetNumReadRequests a second time.
Or maybe this is too weird to fix.
The text was updated successfully, but these errors were encountered: