Repository navigation
buffer: coerce slice parameters consistenly - #9101
thefourtheye wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
It looks like | 0 is used more frequently than ~~ throughout the lib/ code.
17bcccd to
6929c09
Compare
There was a problem hiding this comment.
extremely minor nit... offset |= 0; is even more concise ;-)
6929c09 to
94d3642
Compare
There was a problem hiding this comment.
The Number.isNaN(offset) portion of this conditional should be able to be removed with this change since | will cause invalid inputs to always be zero (whereas + will not).
There was a problem hiding this comment.
nit: 17 can probably be original.length.
There was a problem hiding this comment.
This comment seems a little confusing to me. The offsets are consistently converted to integers (in C++). The real problem is that the end value is calculated in javascript land before it gets passed to C++. If the length calculation (used to determine end) was done inside C++ this wouldn't be an issue.
It's also possible to use floating point numbers with slice() and still get a reasonable result. The only time it becomes an issue is when the end argument is not supplied and start is a floating point number.
There was a problem hiding this comment.
You mean to say the slice implementation would be better done in C++?
Honestly, I would prefer to throw an error if the input is not an integer, which would avoid all this.
There was a problem hiding this comment.
I removed the text in the comments now and improved the commit log a little.
94d3642 to
e648180
Compare
As shown in nodejs#9096, the offset and end value of the `slice` call are coerced to numbers and then passed to `FastBuffer`, which internally truncates the mantissa part if the number is actually a floating point number. This actually affects the new length of the slice calculation. For example, > const original = Buffer.from('abcd'); undefined > original.slice(original.length / 3).toString() 'bc' This happens because, starting value of the slice is 4 / 3, which is 1.33 (approximately). Now, the length of the slice is calculated as the difference between the actual length of the buffer and the starting offset. So, it becomes 2.67 (4 - 1.33). Now, a new `FastBuffer` is constructed, with the following values as parameters, 1. actual buffer object, 2. starting value, which is 1.33 and 3. the length 2.67. The underlying C++ code truncates the numbers and they become 1 and 2. That is why the result is just `bc`. This patch makes sure that all the offsets are coerced to integers before any calculations are done. Fixes: nodejs#9096
e648180 to
9fc562c
Compare
|
LGTM if CI is ok with it: https://ci.nodejs.org/job/node-test-pull-request/4526/ |
commented
Oct 17, 2016
|
For any gage how this should work, would be most similar to |
commented
Oct 17, 2016
|
@trevnorris String's slice also works like this only > const str = "abcd"
undefined
> str.slice(str.length / 3)
'bcd'
> str.slice(str.length / 3, str.length)
'bcd' |
commented
Oct 17, 2016
|
What would the semver-iness of this change be? |
commented
Oct 17, 2016
|
I think it's a bugfix. |
commented
Oct 17, 2016
|
@jasnell I'd classify it as a bug fix, but if anything substantial relies on the old behavior a lot of angry people could show up :-P |
commented
Oct 17, 2016
|
+1 for a bugfix. |
commented
Oct 18, 2016
|
+1 to considering this a bugfix, too. CITGM to account for the “but if anything substantial relies on the old behavior” part: https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/425 |
c133999 to
83c7a88
Compare
commented
Oct 18, 2016
|
Landing as a semver-patch! |
commented
Oct 18, 2016
|
Landed in ee14690 |
|
@jasnell Did my comment about introducing another bug by using |
commented
Oct 27, 2016
|
@trevnorris it looks like there is a good chance of that. What comment are you referring to? This is the only old comment I'm seeing on this thread. |
| function adjustOffset(offset, length) { | ||
| offset = +offset; | ||
| if (offset === 0 || Number.isNaN(offset)) { | ||
| offset |= 0; |
There was a problem hiding this comment.
If you want the floor then please use Math.floor(). Using | allows wrap around. One reason why + was used before.
There was a problem hiding this comment.
String's slice also works like this only
This fails edge cases. For example:
'abcdefg'.slice(-(-1 >>> 0) - 1) === 'abcdefg';
But as this currently stands offset will be coerced to 2 with the above example.
| return 0; | ||
| } | ||
| if (offset < 0) { | ||
| } else if (offset < 0) { |
There was a problem hiding this comment.
Here's where the problem lies. There's no range check before the int32 coercion. A large number could fail this.
| assert.strictEqual( | ||
| buf.slice(buf.length / 3, buf.length).toString(), | ||
| 'bcd' | ||
| ); |
There was a problem hiding this comment.
If we're making the change to operate like String#slice() then edge case tests should be included. e.g.:
const b = Buffer.from('abcdefg');
assert.strictEqual(b.slice(-(-1 >>> 0) + 1).toString(), b.toString());
commented
Oct 28, 2016
|
@cjihrig oh shiet. this was my first time using the review thing before, and didn't realize I needed to properly submit it before the notes could be seen. just did, and that'll show the regression this introduced. |
commented
Oct 28, 2016
|
The old "forgot to submit the review" problem. Got me on multiple PRs the first day I used it :-) |
commented
Oct 28, 2016
|
@trevnorris reverted the |
Checklist
make -j8 test(UNIX), orvcbuild test nosign(Windows) passesAffected core subsystem(s)
buffer
Description of change
As shown in #9096, the offset and
end value of the
slicecall are just coerced to numbers and thenpassed to
FastBuffer, which internally truncates the mantissa partif the number is actually a floating point number. This actually
affects the new length of the slice calculation. For example,
This happens because, starting value of the slice is 4 / 3, which is
1.33 (approximately). Now, the length of the slice is calculated as
the difference between the actual length of the buffer and the starting
offset. So, it becomes 2.67 (4 - 1.33). Now, a new
FastBufferisconstructed, with these values, actual buffer object, starting value
which is 1.33 and the the length 2.67. The underlying C++ code
truncates the numbers and they become 1 and 2. That is why the result
is just
bc.This patch makes sure that all the offsets are coerced to an integer.
Fixes: #9096
cc @nodejs/buffer