-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Only remove listeners left around by soljson #4092
Conversation
Another approach might be to look at the actual version of solc, but I went with this because the explicit set comparison will handle the problem more generally... and cover nightlies and such, so we won't need to identify safe/unsafe versions so rigorously. |
Maybe both reprod
use-truffle-core
truffle init
cat << EOF > ./migrations/1_initial_migration.js
const Migrations = artifacts.require("Migrations");
module.exports = function (deployer) {
Promise.reject(4242);
deployer.deploy(Migrations);
};
EOF
truffle test |
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 like this approach and think it should be extended. I tested it with a rejected promise in migrations and noted soljson's unhandledRejection
listener results in the EMSCRITEN screen dump.
The repro steps for the bug is in a previous comment.
packages/compile-solidity/compilerSupplier/loadingStrategies/LoadingStrategy.js
Outdated
Show resolved
Hide resolved
while reviewing @gnidan's pr, I wanted to test the behavior of current soljson as scaffolded by `truffle init` with a contrived unhandledRejection. That is, adding `Promise.reject(4242)` to a migrations deploy script. depending on the version soljson registers for `uncaughtException` as well as `unhandledRejection`. However BOTH handlers will abort and dump emscripten large generated source to stdout. yuck.
This is controversial, but I think our use case, and space requires erring on the side of caution. [See this discusion](nodejs/node#22822) for more perspective.
- [x] truffle migrate - [ ] truffle test - [ ] truffle compile - [ ] truffle debug - [ ] truffle console - [ ] truffle migrate - [ ] others?
packages/compile-solidity/compilerSupplier/loadingStrategies/Local.js
Outdated
Show resolved
Hide resolved
Also remove `unhandledRejection` to soljson wrapper
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.
some minor nits.
packages/compile-solidity/compilerSupplier/loadingStrategies/Local.js
Outdated
Show resolved
Hide resolved
packages/compile-solidity/compilerSupplier/loadingStrategies/VersionRange.js
Outdated
Show resolved
Hide resolved
packages/compile-solidity/compilerSupplier/loadingStrategies/VersionRange.js
Outdated
Show resolved
Hide resolved
Co-authored-by: amal <cds.sudama@gmail.com>
Nice one @gnidan ! |
const newListeners = listeners.filter( | ||
(listener) => !markedListeners[eventName].has(listener), | ||
); | ||
|
||
if (execeptionHandler) { | ||
process.removeListener("uncaughtException", execeptionHandler); | ||
for (const listener of newListeners) { | ||
process.removeListener(eventName, listener); | ||
} |
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 condensed to:
for (const eventName in markedListeners) {
const marked = markedListeners[eventName];
process.listeners(eventName).forEach((listener) => {
if (!marked.has(listener)) {
process.removeListener(eventName, listener);
}
});
}
And if we change markedListeners
to a Map<string, Array<AnyFunction>
it could be:
for (const [eventName, marked] of markedListeners) {
process.listeners(eventName).forEach((listener) => {
if (!marked.has(listener)) {
process.removeListener(eventName, listener);
}
});
}
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.
Borrowed the first one :) Thanks @davidmurdoch!
(I feel like there's a joke here that begins "how many engineers does it take to add a mutex lock?" :) Thanks @cds-amal and @davidmurdoch! Will merge when green. |
for (const eventName in markedListeners) { | ||
const marked = markedListeners[eventName]; | ||
for (const listener of process.listeners(eventName)) { | ||
if (!marked.has(listener)) { | ||
process.removeListener(eventName, listener); | ||
} |
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.
nice! Thank you!
So, here's a hypothesis for the
uncaughtException
business in compile-solidity.Solidity upgraded Emscripten from v1.35.4 to v1.37.21 in solc v0.5.1 (in this PR). Inspecting the Emscripten changelog, this issue was closed as part of v1.36.6. Looks like the fix here may have changed buggy behavior that left
uncaughtException
s to linger.Since we support old Solidity and need to handle pre-v0.5.1 behavior, this PR proposes that we alter the listener removal by first capturing the listeners that existed before loading solc and then removing only those listeners that are new after loading solc.
This is a different proposed solution than #4091... I haven't done any digging re: that PR's hypothesis that we must remove listeners for
unhandledRejection
, but I suspect that may be a red herring. This PR should address the "exits violently" part of #4090 (as well as many other issues over the past however-long)