-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
buffer: coerce slice parameters consistenly #9101
buffer: coerce slice parameters consistenly #9101
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM if CI is green
@@ -807,7 +807,7 @@ Buffer.prototype.toJSON = function() { | |||
|
|||
|
|||
function adjustOffset(offset, length) { | |||
offset = +offset; | |||
offset = ~~offset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like | 0
is used more frequently than ~~
throughout the lib/
code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cjihrig Sure. Changed it now.
17bcccd
to
6929c09
Compare
@@ -807,7 +807,7 @@ Buffer.prototype.toJSON = function() { | |||
|
|||
|
|||
function adjustOffset(offset, length) { | |||
offset = +offset; | |||
offset = offset | 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extremely minor nit... offset |= 0;
is even more concise ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
{ | ||
// Test included in https://github.com/nodejs/node/issues/9096 | ||
// If the offset or ending value provided is a floating point number, it | ||
// should be coerced to integer consistenly. Otherwise the actual length of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: consistently
6929c09
to
94d3642
Compare
@@ -807,7 +807,7 @@ Buffer.prototype.toJSON = function() { | |||
|
|||
|
|||
function adjustOffset(offset, length) { | |||
offset = +offset; | |||
offset |= 0; | |||
if (offset === 0 || Number.isNaN(offset)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with @mscdex’ suggestion
// the slice calculation will be messed up. | ||
const original = Buffer.from('1234567890ABCDEFG', 'ascii'); | ||
const chunk1 = original.slice(0, original.length / 3); | ||
const chunk2 = original.slice(original.length / 3, 17); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: 17
can probably be original.length
.
// Test included in https://github.com/nodejs/node/issues/9096 | ||
// If the offset or ending value provided is a floating point number, it | ||
// should be coerced to integer consistently. Otherwise the actual length of | ||
// the slice calculation will be messed up. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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/ |
For any gage how this should work, would be most similar to |
@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' |
What would the semver-iness of this change be? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I think it's a bugfix. |
@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 |
+1 for a bugfix. |
+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
Landing as a semver-patch! |
As shown in #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: #9096 PR-URL: #9101 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Brian White <[email protected]>
Landed in ee14690 |
As shown in #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: #9096 PR-URL: #9101 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Brian White <[email protected]>
As shown in #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: #9096 PR-URL: #9101 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Brian White <[email protected]>
@jasnell Did my comment about introducing another bug by using |
@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. |
@@ -807,11 +807,10 @@ Buffer.prototype.toJSON = function() { | |||
|
|||
|
|||
function adjustOffset(offset, length) { | |||
offset = +offset; | |||
if (offset === 0 || Number.isNaN(offset)) { | |||
offset |= 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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());
@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. |
The old "forgot to submit the review" problem. Got me on multiple PRs the first day I used it :-) |
@trevnorris reverted the |
This is a partial revert of 14d1a8a, which coerced the offset of Buffer#slice() using the | operator. This causes some edge cases to be handled incorrectly. This commit restores the old behavior, but converts offsets to integers using Math.trunc(). This commit does not revert any tests, and adds an additional regression test. Refs: nodejs#9096 Refs: nodejs#9101 PR-URL: nodejs#9341 Reviewed-By: Sakthipriyan Vairamani <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Brian White <[email protected]> Reviewed-By: Trevor Norris <[email protected]>
This is a partial revert of 14d1a8a, which coerced the offset of Buffer#slice() using the | operator. This causes some edge cases to be handled incorrectly. This commit restores the old behavior, but converts offsets to integers using Math.trunc(). This commit does not revert any tests, and adds an additional regression test. Refs: #9096 Refs: #9101 PR-URL: #9341 Reviewed-By: Sakthipriyan Vairamani <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Brian White <[email protected]> Reviewed-By: Trevor Norris <[email protected]>
As shown in #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: #9096 PR-URL: #9101 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Brian White <[email protected]>
This is a partial revert of 14d1a8a, which coerced the offset of Buffer#slice() using the | operator. This causes some edge cases to be handled incorrectly. This commit restores the old behavior, but converts offsets to integers using Math.trunc(). This commit does not revert any tests, and adds an additional regression test. Refs: #9096 Refs: #9101 PR-URL: #9341 Reviewed-By: Sakthipriyan Vairamani <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Brian White <[email protected]> Reviewed-By: Trevor Norris <[email protected]>
As shown in #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: #9096 PR-URL: #9101 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Brian White <[email protected]>
This is a partial revert of 14d1a8a, which coerced the offset of Buffer#slice() using the | operator. This causes some edge cases to be handled incorrectly. This commit restores the old behavior, but converts offsets to integers using Math.trunc(). This commit does not revert any tests, and adds an additional regression test. Refs: #9096 Refs: #9101 PR-URL: #9341 Reviewed-By: Sakthipriyan Vairamani <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Brian White <[email protected]> Reviewed-By: Trevor Norris <[email protected]>
This LTS release comes with 144 commits. This includes 47 that are docs related, 46 that are test related, 15 which are build / tools related, and 9 commits which are updates to dependencies Notable Changes: * buffer: - coerce slice parameters consistently (Sakthipriyan Vairamani (thefourtheye)) #9101 * deps: - *npm*: - upgrade npm to 3.10.9 (Kat Marchán) #9286 - *V8*: - Various fixes to destructuring edge cases - cherry-pick 3c39bac from V8 upstream (Cristian Cavalli) #9138 - cherry pick 7166503 from upstream v8 (Cristian Cavalli) #9173 * gtest: - the test reporter now outputs tap comments as yamlish (Johan Bergström) #9262 * inspector: - inspector now prompts user to use 127.0.0.1 rather than localhost (Eugene Ostroukhov) #9451 * tls: - fix memory leak when writing data to TLSWrap instance during handshake (Fedor Indutny) #9586 PR-URL: #9735
This LTS release comes with 144 commits. This includes 47 that are docs related, 46 that are test related, 15 which are build / tools related, and 9 commits which are updates to dependencies Notable Changes: * buffer: - coerce slice parameters consistently (Sakthipriyan Vairamani (thefourtheye)) #9101 * deps: - *npm*: - upgrade npm to 3.10.9 (Kat Marchán) #9286 - *V8*: - Various fixes to destructuring edge cases - cherry-pick 3c39bac from V8 upstream (Cristian Cavalli) #9138 - cherry pick 7166503 from upstream v8 (Cristian Cavalli) #9173 * gtest: - the test reporter now outputs tap comments as yamlish (Johan Bergström) #9262 * inspector: - inspector now prompts user to use 127.0.0.1 rather than localhost (Eugene Ostroukhov) #9451 * tls: - fix memory leak when writing data to TLSWrap instance during handshake (Fedor Indutny) #9586 PR-URL: #9735
This LTS release comes with 144 commits. This includes 47 that are docs related, 46 that are test related, 15 which are build / tools related, and 9 commits which are updates to dependencies Notable Changes: * buffer: - coerce slice parameters consistently (Sakthipriyan Vairamani (thefourtheye)) #9101 * deps: - *npm*: - upgrade npm to 3.10.9 (Kat Marchán) #9286 - *V8*: - Various fixes to destructuring edge cases - cherry-pick 3c39bac from V8 upstream (Cristian Cavalli) #9138 - cherry pick 7166503 from upstream v8 (Cristian Cavalli) #9173 * gtest: - the test reporter now outputs tap comments as yamlish (Johan Bergström) #9262 * inspector: - inspector now prompts user to use 127.0.0.1 rather than localhost (Eugene Ostroukhov) #9451 * tls: - fix memory leak when writing data to TLSWrap instance during handshake (Fedor Indutny) #9586 PR-URL: #9735
This LTS release comes with 144 commits. This includes 47 that are docs related, 46 that are test related, 15 which are build / tools related, and 9 commits which are updates to dependencies Notable Changes: * buffer: - coerce slice parameters consistently (Sakthipriyan Vairamani (thefourtheye)) nodejs/node#9101 * deps: - *npm*: - upgrade npm to 3.10.9 (Kat Marchan) nodejs/node#9286 - *V8*: - Various fixes to destructuring edge cases - cherry-pick 3c39bac from V8 upstream (Cristian Cavalli) nodejs/node#9138 - cherry pick 7166503 from upstream v8 (Cristian Cavalli) nodejs/node#9173 * gtest: - the test reporter now outputs tap comments as yamlish (Johan Bergstrom) nodejs/node#9262 * inspector: - inspector now prompts user to use 127.0.0.1 rather than localhost (Eugene Ostroukhov) nodejs/node#9451 * tls: - fix memory leak when writing data to TLSWrap instance during handshake (Fedor Indutny) nodejs/node#9586 PR-URL: nodejs/node#9735 Signed-off-by: Ilkka Myller <[email protected]>
This LTS release comes with 144 commits. This includes 47 that are docs related, 46 that are test related, 15 which are build / tools related, and 9 commits which are updates to dependencies Notable Changes: * buffer: - coerce slice parameters consistently (Sakthipriyan Vairamani (thefourtheye)) nodejs/node#9101 * deps: - *npm*: - upgrade npm to 3.10.9 (Kat Marchan) nodejs/node#9286 - *V8*: - Various fixes to destructuring edge cases - cherry-pick 3c39bac from V8 upstream (Cristian Cavalli) nodejs/node#9138 - cherry pick 7166503 from upstream v8 (Cristian Cavalli) nodejs/node#9173 * gtest: - the test reporter now outputs tap comments as yamlish (Johan Bergstrom) nodejs/node#9262 * inspector: - inspector now prompts user to use 127.0.0.1 rather than localhost (Eugene Ostroukhov) nodejs/node#9451 * tls: - fix memory leak when writing data to TLSWrap instance during handshake (Fedor Indutny) nodejs/node#9586 PR-URL: nodejs/node#9735 Signed-off-by: Ilkka Myller <[email protected]>
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
slice
call 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
FastBuffer
isconstructed, 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