refactor: lazily hook into child_process in asar_init (#18576)
Previously we loaded both fs and child_process and then hooked into the returned value, relying on the module cache to keep our modifications and give them to everyone. Loading child_process took in excess of 20ms though so instead of loading it and then hooking in. We intercept all Module load requests, and when the first one for `child_process` comes in, we wrap the appropriate methods and then never touch it again.
This commit is contained in:
parent
cb4579fe28
commit
cec61d010b
1 changed files with 31 additions and 16 deletions
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
const asar = process._linkedBinding('atom_common_asar')
|
const asar = process._linkedBinding('atom_common_asar')
|
||||||
const assert = require('assert')
|
const v8Util = process._linkedBinding('atom_common_v8_util')
|
||||||
const { Buffer } = require('buffer')
|
const { Buffer } = require('buffer')
|
||||||
const childProcess = require('child_process')
|
const Module = require('module')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const util = require('util')
|
const util = require('util')
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@
|
||||||
error = new Error(`Invalid package ${asarPath}`)
|
error = new Error(`Invalid package ${asarPath}`)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
assert.fail(`Invalid error type "${errorType}" passed to createError.`)
|
throw new Error(`Invalid error type "${errorType}" passed to createError.`)
|
||||||
}
|
}
|
||||||
return error
|
return error
|
||||||
}
|
}
|
||||||
|
@ -703,16 +703,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executing a command string containing a path to an asar
|
|
||||||
// archive confuses `childProcess.execFile`, which is internally
|
|
||||||
// called by `childProcess.{exec,execSync}`, causing
|
|
||||||
// Electron to consider the full command as a single path
|
|
||||||
// to an archive.
|
|
||||||
const { exec, execSync } = childProcess
|
|
||||||
childProcess.exec = invokeWithNoAsar(exec)
|
|
||||||
childProcess.exec[util.promisify.custom] = invokeWithNoAsar(exec[util.promisify.custom])
|
|
||||||
childProcess.execSync = invokeWithNoAsar(execSync)
|
|
||||||
|
|
||||||
function invokeWithNoAsar (func) {
|
function invokeWithNoAsar (func) {
|
||||||
return function () {
|
return function () {
|
||||||
const processNoAsarOriginalValue = process.noAsar
|
const processNoAsarOriginalValue = process.noAsar
|
||||||
|
@ -732,10 +722,35 @@
|
||||||
overrideAPISync(fs, 'copyFileSync')
|
overrideAPISync(fs, 'copyFileSync')
|
||||||
|
|
||||||
overrideAPI(fs, 'open')
|
overrideAPI(fs, 'open')
|
||||||
overrideAPI(childProcess, 'execFile')
|
|
||||||
overrideAPISync(process, 'dlopen', 1)
|
overrideAPISync(process, 'dlopen', 1)
|
||||||
overrideAPISync(require('module')._extensions, '.node', 1)
|
overrideAPISync(Module._extensions, '.node', 1)
|
||||||
overrideAPISync(fs, 'openSync')
|
overrideAPISync(fs, 'openSync')
|
||||||
overrideAPISync(childProcess, 'execFileSync')
|
|
||||||
|
// Lazily override the child_process APIs only when child_process is fetched the first time
|
||||||
|
const originalModuleLoad = Module._load
|
||||||
|
Module._load = (request, ...args) => {
|
||||||
|
const loadResult = originalModuleLoad(request, ...args)
|
||||||
|
if (request === 'child_process') {
|
||||||
|
if (!v8Util.getHiddenValue(loadResult, 'asar-ready')) {
|
||||||
|
v8Util.setHiddenValue(loadResult, 'asar-ready', true)
|
||||||
|
// Just to make it obvious what we are dealing with here
|
||||||
|
const childProcess = loadResult
|
||||||
|
|
||||||
|
// Executing a command string containing a path to an asar
|
||||||
|
// archive confuses `childProcess.execFile`, which is internally
|
||||||
|
// called by `childProcess.{exec,execSync}`, causing
|
||||||
|
// Electron to consider the full command as a single path
|
||||||
|
// to an archive.
|
||||||
|
const { exec, execSync } = childProcess
|
||||||
|
childProcess.exec = invokeWithNoAsar(exec)
|
||||||
|
childProcess.exec[util.promisify.custom] = invokeWithNoAsar(exec[util.promisify.custom])
|
||||||
|
childProcess.execSync = invokeWithNoAsar(execSync)
|
||||||
|
|
||||||
|
overrideAPI(childProcess, 'execFile')
|
||||||
|
overrideAPISync(childProcess, 'execFileSync')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loadResult
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
|
Loading…
Reference in a new issue