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
Fix bugs in the Grow feature #134
Conversation
Which will make reserved header size incorrect.
When Grow() is called, it's possible that the header size will increase, which makes the reserved bytes calculated before the call not enough. Since the max reserved bytes is 10 or 14, which it's relatively small. I think it's okay to use the fixed size.
Hi @ZekeLu, can you please explain which exactly issues you are fixing here? |
Hi @gobwas, sorry that I don't make it clear. The commits are organized in this way: first, it adds a test to reproduce the issue, then a commit fixing that issue is followed. Maybe it's a little easier to review the commits one by one. I will submit this comment first so that you can get my reply asap. I will explain more in the next comment. |
Here is the first issue: The writer is created with
This issue is reproduced in d562c93 and fixed in b0474c8. Lines 286 to 296 in 2effe5e
Lines 271 to 273 in 2effe5e
Lines 339 to 346 in 2effe5e
|
Here is the second issue: Again, the writer is created with
When the buffer grows, the offset is kept (see line 350 below): Lines 339 to 351 in 2effe5e
This time, we set the message size to Lines 31 to 46 in 2effe5e
And later, when
panic with Lines 472 to 500 in 2effe5e
|
I'm sorry that the explanation looks like a mess. But it's all about calculation, and I don't know how to explain the issues more clearly. And the final commit 59a2d64 is to fix bugs introduced by its previous commit. I intentionally not to meld it into the previous commit because the bugs are just covered by the That's all. Thank you! |
Hey @ZekeLu, Thanks for explanation! I think it is a good idea to add unit tests for each (if multiple) mentioned issues. It would be easier to reproduce the bugs and understand your fixes. Can you add it please? Anyway I will delve into this on weekend, so thanks for reporting and fixing. upd. Ah, I see one unit test already, so maybe only one unit test is missing (the one you mentioned that is covered by autobahn)? |
Yes, I'm going to add unit tests for that. Thanks for your time! |
Hey @ZekeLu, that's what I was thinking of! Great, thanks! |
Kindly ping @gobwas. Any updates on this PR? BTW, do you have a plan to release v1.1.0? |
Hey @ZekeLu! Sorry for being silent, had pretty busy days. Anyway, I just finished delving into your work and want to thank you again for finding out this bugs! I did cherry-pick most of your commits. However, I didn't pick the 458fafb not because I didn't like the idea of simplification, but because it seemed to me that it takes too many places to change (and moreover produced some issues which you fixed in 6th comit?). So I fixed it in other way, please check the master branch if it works for you. Regarding release, yeah, I was just waiting if anyone will find some inconvinience and then your bug fixes arrived, so I wanted to include them as well into v1.1.0. So if master works for your use cases, lets do release-candidate today and true release later on this week? 🎉 |
Hey @gobwas, thank you for your review! I'm very appreciated for your excellent work! I agree that 458fafb touches too many places, and I don't have the confidence that it doesn't bring any new bugs. I'm appreciated that you find a better way to fix it. I feel relaxed now. The schedule is good to me. I'm going to test my use cases, and will feedback later. Thank you very much! |
@gobwas I'm sorry but the changes failed my test. I guess here is the problem (see the comments below): func (w *Writer) Grow(n int) {
var (
size = len(w.raw)
offset = len(w.raw) - len(w.buf)
buffered = w.Buffered()
)
for cap := size - offset - buffered; cap < n; {
size = ceilPowerOfTwo(offset + buffered + n)
// the size will be greater than the payload size most of the time,
// and I think we should use the payload size to calculate the header size.
offset = headerSize(w.state, size)
cap = size - offset - buffered
}
if size <= len(w.raw) {
panic("wsutil: buffer grow leads to its reduce")
}
p := make([]byte, size)
// if the header size grows, the payload should be shifted,
// but the copy below does not shift the payload.
copy(p, w.raw[:offset+buffered])
w.raw = p
w.buf = w.raw[offset:]
} Inspired by your changes, I think we can simply do it like this ( diff --git a/wsutil/writer.go b/wsutil/writer.go
index 6941dc0..41a6016 100644
--- a/wsutil/writer.go
+++ b/wsutil/writer.go
@@ -336,18 +336,22 @@ func ceilPowerOfTwo(n int) int {
return n
}
func (w *Writer) Grow(n int) {
var (
- offset = len(w.raw) - len(w.buf)
- size = ceilPowerOfTwo(offset + w.n + n)
+ oldOffset = len(w.raw) - len(w.buf)
+ newOffset = headerSize(w.state, w.n+n)
+ size = ceilPowerOfTwo(newOffset + w.n + n)
)
if size <= len(w.raw) {
panic("wsutil: buffer grow leads to its reduce")
}
p := make([]byte, size)
- copy(p, w.raw[:offset+w.n])
+ copy(p[newOffset-oldOffset:], w.raw[:oldOffset+w.n])
w.raw = p
- w.buf = w.raw[offset:]
+ w.buf = w.raw[newOffset:]
} This change passed my tests. I will send another PR so that it will run the I know that you had been super busy recently, sorry to occupy your spare time! ☕ Update: I just realized that I can not send a PR based on cfd0d39 (Github required me to pick a branch or tag as the base). So the PR #138 is based on the current |
Hey @ZekeLu, yeah, there was a bug with that old and new offsets, nice catch, thank you! Which tests did it fail? Can you commit some? |
It's a test in another repository which depends on your excellent package: Now you ask, I will create a simple test and commit it later. |
Thanks! Will get back to it tomorrow Moscow Time. |
Then I will create the test tomorrow morning Beijing Time. It's very late here now (~ 3 AM). |
Sure! Night! |
Good morning @gobwas, I just forced pushed to #138. As usual, test first, fix follows. I have changed the test code a little so that it covers more cases:
The section below is off-topic, I'm not sure is it okay to discuss it here. Since we are handling revered space for header, I thought that we should use update: here is the doc I wanted to add: 8fa6aa1 |
Hey @ZekeLu, hope you are well! Regarding the doc, seems that I missed you update; however I added it also, but fill free to open separate PR to clarify things better, if you feel we need it! Waiting for your feedback regarding fix! upd. It's fun to see that comments to |
Hey @gobwas, hope you are well too! It feels like pair programming, and it's good! I took a carefully look into your changes, and found that I made some mistakes before:
Thank you for your fix! I think everything is clear and we could close this PR now. I really learn a lot from you! Thank you again! ☕ 🤝 |
Hey @ZekeLu! Great to hear that! Yeah, it was nice to work together on this! |
Thanks for your excellent work!
https://github.com/chromedp/chromedp depends on this package, and it fails to send large requests due to the lack of fragmentation support in Chrome (reported here: ChromeDevTools/devtools-protocol#175). Now that
Grow()
is added to this package, I want to address this issue on the client side. It works like a charm! Thank you very much!I found some issues though. So here is the pull request.
BTW,
DisableFlush()
is supposed to be used to enable auto growing of the buffer, right? Is it better to call itEnableAutoGrow()
?