-
Notifications
You must be signed in to change notification settings - Fork 7.5k
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
Fixing an issue where patching functions into Object.prototype makes the event removal crash. #4669
Conversation
src/js/utils/events.js
Outdated
@@ -351,8 +351,12 @@ export function off(elem, type, fn) { | |||
|
|||
// Are we removing all bound events? | |||
if (!type) { | |||
for (const t in data.handlers) { | |||
removeType(t); | |||
if (!!data && !!data.handlers) { |
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.
Why do this check here? If data.handlers
doesn't exist, we should already have exited on line 338.
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 are right. It appears as if I was overly cautious when looking for the reason of data.handlers
being undefined
.
src/js/utils/events.js
Outdated
removeType(t); | ||
if (!!data && !!data.handlers) { | ||
for (const t in data.handlers) { | ||
if (!!data.handlers && !!data.handlers.hasOwnProperty && data.handlers.hasOwnProperty(t)) { |
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.
does this mean that if hasOwnProperty
is missing for whatever reason, we'll end up not actually removing the handler?
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 just went in and reconstructed the situation.
I called player.off("")
to get into the if (!type)
statement.
It had data.handlers
filled up and in the loop removed one child after another. It seems like after the last own property is removed data.handler gets removed, as when it starts processing the prototype properties data
actually is {}
.
So in the end
if (!type) {
for (const t in data.handlers) {
if (data.handlers) {
removeType(t);
}
}
return;
}
would totally do the trick.
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.
Is player.off('')
what causing issues here? Are there other examples?
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 hit this problem at work in a more complex code base. I cannot exactly find the instance/code point that caused it.
player.off('')
was the most condensed trigger I could find to hit that code. It appears any falsy input would trigger the loop and thus the error.
I am constantly removing and adding players though... Maybe it's caused by one of the 3 xxx.off()
calls in evented.js 369, track-list.js 115 and plugin.js 291? target.on('dispose', () => target.off());
at evented.js 369 seems especially likely.
src/js/utils/url.js
Outdated
@@ -85,6 +85,10 @@ export const parseUrl = function(url) { | |||
document.body.removeChild(div); | |||
} | |||
|
|||
if (details.protocol === '') { |
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.
seems like this belongs in separate PR.
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 are right. This is a separate topic.
It's my first time committing to a bigger project with such a refined build tool chain and I did not want to (and I believe it didn't let me) push failing code. Deemed that more important than singling out a secondary fix which is closed due to inactivity anyway and wait for it to be accepted before committing this PR.
If you prefer I can revert this here and add it to a separate PR.
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.
Thanks for contributing!
Making multiple PRs is generally better because then a single topic isn't blocking another topic that has been approved and the discussion can focus on the thing issue at hand.
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.
Ok. I will move it out from here.
Thanks for the PR! I made some comments. |
So, I think I figured out the root cause of the issue. Video.js has a feature where on a component or the player if you call |
You are right in that But that does not affect the problem I was aiming to fix. It still fails on for (const t in data.handlers) {
if (data.handlers) {
removeType(t);
}
} |
Oh, I see. |
I did the change locally and The two obvious solutions would be if (data.handlers && Object.prototype.hasOwnProperty.call(data.handlers, t)) and if (Object.prototype.hasOwnProperty.call(data.handlers || {}, t)) Which one do you prefer? |
Probably the second one but I don't understand why |
That would be, because line 30 of events.js deletes the current So once the last own property is removed With "make a test case for this" you mean like unit test? Currently there are no unit tests for the events.js and I have never done unit testing on JS before - I don't feel up to the task of starting a new test suite. |
improved ownProperty-check for monkey-patched Object.prototype in off()
Oh, I see. I was able to reproduce it locally. So, the issue here is really that |
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.
Good catch. Thanks!
No problem. |
Are we still missing some step that I should perform or is anything else still off here? |
Yup, we hadn't merged it yet. We'll be merging things in this week :) |
Description
I found a problem, where adding custom functions to Object.prototype made the event-off function crash upon iterating over all properties of an object.
I fixed it by checking for
hasOwnProperty
.As the tests failed for me on Win10 IE11 I also fixed issue #3100 that addressed this.Specific Changes proposed
I added an if-clause to url.js‘sparseUrl
to add the current window.location.protocol if the protocol of the given url is empty (or//
).I also added 2 if statements to events.js‘s.off
in the "type is falsy" if to check that data and data.handler is present (occasionally was undefined with me) and within the loop check if data.handler has t as it‘s own propertyI added an if statement to events.js‘s off in the
if (!type)
to check that data.handler is still present and hast
as its own property while running the for loop. This way it won‘t try to remove monkey-patched properties.To make the loop only run in the case of an omitted type parameter the surrounding if was corrected from
(!type)
to(type === undefined)
Requirements Checklist