-
Notifications
You must be signed in to change notification settings - Fork 15.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
Don't crash when calling stale remote listeners #8357
Conversation
This seems helpful, could you add a spec for this as well? |
: eventsAttached[eventName] === callIntoRenderer | ||
}) | ||
|
||
if (remoteEvents && remoteEvents.length > 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.
I don't think Array.prototype.filter
can return null so I think you can drop the first part of this check and just use remoteEvent.length > 0
let message = `Attempting to call a function in a renderer window that has been closed or released.` + | ||
`\nFunction provided here: ${meta.location}` | ||
|
||
if (!args || args.length === 0) return message |
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.
args
will never be passed as null
by the calling method so I think you can just use arg.length === 0
here.
@@ -146,6 +146,30 @@ const throwRPCError = function (message) { | |||
throw error | |||
} | |||
|
|||
const rendererMissingErrorMessage = function (meta, args, callIntoRenderer) { |
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.
Since this is a new method, feel free to make this a =>
function if you'd like.
message += `\nRemote event names:` | ||
remoteEvents.forEach((eventName) => { | ||
message += ` ${eventName} ` | ||
}) |
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 be simplified to:
message += `\nRemote event names: ${remoteEvents.join(' ')}`
This is great! Should save people time and energy when debugging. 👍 |
@kevinsawicki updated with your comments. As for the spec, I'm happy to write one but unsure where it should go? |
Usually they go in See #6963 for a recent pull request with a test example. |
@kevinsawicki I was able to get a spec in for the |
I'll take a look 👀 |
if (args.length === 0) return message | ||
if (!args[0].sender || !args[0].sender._events) return message | ||
|
||
const eventsAttached = args[0].sender._events |
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.
Could this use https://nodejs.org/api/events.html#events_emitter_eventnames to get an array of event names?
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.
We could, but we'll get all the events. We need to compare the event handler with callIntoRenderer
to know if it's a remote listener, so we'll still have to iterate.
@CharlieHess I updated the spec, let me know what you think. |
1b979b7
to
55a245f
Compare
@kevinsawicki new spec looks good, thanks! ✨ |
if (remoteEvents.length > 0) { | ||
message += `\nRemote event names: ${remoteEvents.join(', ')}` | ||
remoteEvents.forEach((eventName) => { | ||
sender.removeListener(eventName, callIntoRenderer) |
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.
Would be great to assert this happens as well in the spec, perhaps by asserting listenerCount()
goes down for each event name being listened to.
@@ -146,6 +146,28 @@ const throwRPCError = function (message) { | |||
throw error | |||
} | |||
|
|||
const rendererMissingErrorMessage = (meta, args, callIntoRenderer) => { |
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.
Since this method now removes the listeners as well, I think perhaps it should be renamed and do the console.warn
directly in here.
Maybe a name like logMissingRendererMessageAndRemoveListeners
?
388e8b8
to
08b8ebd
Compare
If possible, we'll dig into the function args and print the ones that are attached remotely.
f364298
to
330ac5f
Compare
Thanks for this @CharlieHess 👍 |
When Electron tries to call a method in a deceased renderer it throws an exception. This behavior makes the
remote
module a bit of a hornet's nest, because it's quite easy to listen to events from the main process but often non-trivial to clean them up properly. Instead of crashing, we could dig into the underlyingEventEmitter
and remove the listeners that are hooked tocallIntoRenderer
. We could also display aconsole.warn
so that the user knows they did something bad and still has a chance to fix it.In addition this PR adds the names of the remote events to the error message, to make them easier to find. Increasingly often methods are wrapped in higher-level abstractions such as
Promise
orObservable
someta.location
is not enough information on its own. The new warning looks like: