-
Notifications
You must be signed in to change notification settings - Fork 949
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
Avoid reading outside of collection bounds #407
base: main
Are you sure you want to change the base?
Avoid reading outside of collection bounds #407
Conversation
Hey. This looks nice to me. How this reflects on the byte size though? Maybe you could provide a small jsperf as well? |
@@ -671,8 +671,10 @@ setDocument = Sizzle.setDocument = function( node ) { | |||
|
|||
// Fall back on getElementsByName | |||
elems = context.getElementsByName( id ); | |||
length = elems.length; | |||
i = 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.
This could moved to the body of a for
right?
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.
Yes, for both i
and length
. However, i
was already outside of the for
, so I decided to follow the existing style.
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.
Oh, that because of the https://contribute.jquery.org/style-guide/js/#good-examples, i.e. it should be fine to put i
to the body, as long its initialised on top of the scope, like we doing here – https://github.com/jquery/jquery/blob/692f9d4db30c9c6c4f6bc76005cf153586202fa6/src/effects.js#L614 :)
@@ -671,8 +671,10 @@ setDocument = Sizzle.setDocument = function( node ) { | |||
|
|||
// Fall back on getElementsByName | |||
elems = context.getElementsByName( id ); | |||
length = elems.length; |
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.
NodeList#length can be an element in IE<9 (and we should have a test where that is the case on this line). cf. f6e2fc5#diff-7d34356c0b7229dd5da8b6c7711b32b7R1733
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.
So, something like this?
if (typeof elem.length === 'number') {
fastPath();
} else {
slowPathForLegacyBrowsers();
}
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.
Yes, provided we can get it without excessive file size increase.
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.
for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
@@ -702,11 +704,13 @@ setDocument = Sizzle.setDocument = function( node ) { | |||
tmp = [], | |||
i = 0, | |||
// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too | |||
results = context.getElementsByTagName( tag ); | |||
results = context.getElementsByTagName( tag ), | |||
length = results.length; |
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.
Same problem here.
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.
Done.
@@ -1054,17 +1058,19 @@ Sizzle.uniqueSort = function( results ) { | |||
var elem, | |||
duplicates = [], | |||
j = 0, | |||
i = 0; | |||
i = 0, | |||
length = results.length; |
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.
Same problem here.
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.
Done.
Consider the following collection: const array = ['a', 'b', 'c']; Retrieving `array[0]` can be done relatively quickly. However, when the property doesn’t exist on the receiver, JavaScript engines must continue to look up the prototype chain until either the property is found or the chain ends. This is inherently slower than *not* doing any prototype chain lookups. Retrieving an out-of-bounds index, e.g. `array[3]`, triggers this scenario, resulting in decreased performance. This patch changes the way some loops are written to avoid running into the slow case unnecessarily.
88e5e6d
to
893e3c5
Compare
This is pretty big... can you put together a jsPerf or other benchmark (example, and yes I'm aware of the irony) showing the value?
|
i = 0; | ||
while ( (elem = elems[i++]) ) { | ||
for ( ; i !== length && (elem = elems[ i ]) != null; i++ ) { |
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 is probably not an issue, but I feel like i < length
is safer.
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 < length
would definitely be an issue, because length
might be a DOM node in IE<9.
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.
makes sense.
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.
Perhaps we could put in a comment relating that as a reminder.
If the Chrome perf quirk was the main driver for this, that has been fixed. |
|
Consider the following collection:
Retrieving
array[0]
can be done relatively quickly. However, when the property doesn’t exist on the receiver, JavaScript engines must continue to look up the prototype chain until either the property is found or the chain ends. This is inherently slower than not doing any prototype chain lookups. Retrieving an out-of-bounds index, e.g.array[3]
, triggers this scenario, resulting in decreased performance.This patch changes the way some loops are written to avoid running into the slow case unnecessarily.
Similar patch for jQuery: jquery/jquery#3769