mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 11:13:21 +00:00
fix(javascript): stop an Electron alias walk at a read before its initializer
The alias walk followed `var saved=s; var s=n(K)` to the later Electron load although `saved` captured undefined. Each hop now checks, as the consumer read already did, that the aliased binding's stable origin is available at that read. The walk also shares one visited set instead of copying it at every hop. Refs #4490 Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
This commit is contained in:
1 parent
39c820c90d
commit
98540f24e0
2 files changed
+28
-14
No files matched your search
@@ -882,17 +882,7 @@ export function* indexJavaScriptElectronIdentitySteps(
|
||||
const originAvailableAtRead = (
|
||||
binding: JavaScriptSemanticBindingState,
|
||||
read: t.Node,
|
||||
): boolean => {
|
||||
if (
|
||||
binding.directOrigins.length > 0 ||
|
||||
semanticStableInitializer(binding, state) === undefined
|
||||
)
|
||||
return true;
|
||||
const access = semanticBindingAtRead(binding, read, state);
|
||||
// An unresolved activation can still carry a possible identity, while an
|
||||
// ordered read before its initializer cannot refer to that value.
|
||||
return access.status !== "ordered" || access.hasDefiniteInitializer;
|
||||
};
|
||||
): boolean => originAvailableAt(binding, read, state);
|
||||
const rootOrigin = (root: t.Node): readonly string[] | undefined => {
|
||||
if (t.isIdentifier(root)) {
|
||||
if (semanticResolutionBlocked(state, root, root.name)) return undefined;
|
||||
@@ -1139,16 +1129,35 @@ const electronRequireOrigin = (
|
||||
semanticRequireOrigin(node, state) ??
|
||||
semanticBundledRequireOrigin(node, state);
|
||||
|
||||
/** Whether a read can see the binding's stable origin rather than an earlier value. */
|
||||
const originAvailableAt = (
|
||||
binding: JavaScriptSemanticBindingState,
|
||||
read: t.Node,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
): boolean => {
|
||||
if (
|
||||
binding.directOrigins.length > 0 ||
|
||||
semanticStableInitializer(binding, state) === undefined
|
||||
)
|
||||
return true;
|
||||
const access = semanticBindingAtRead(binding, read, state);
|
||||
// An unresolved activation can still carry a possible identity, while an
|
||||
// ordered read before its initializer cannot refer to that value.
|
||||
return access.status !== "ordered" || access.hasDefiniteInitializer;
|
||||
};
|
||||
|
||||
/**
|
||||
* General provenance only knows literal `require`, so a bundled external held
|
||||
* in one binding and destructured from another (`const s=n(K);const{X}=s`)
|
||||
* is followed here through stable lexical aliases. Like provenance, a hop
|
||||
* stops at a rebindable binding that direct eval may have changed.
|
||||
* stops at a rebindable binding that direct eval may have changed, and at an
|
||||
* alias read that runs before the aliased binding's initializer. The chain has
|
||||
* one alias per hop, so one visited set serves the whole walk.
|
||||
*/
|
||||
const bindingOrigin = (
|
||||
binding: JavaScriptSemanticBindingState,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
visited: ReadonlySet<string> = new Set(),
|
||||
visited: Set<string> = new Set(),
|
||||
): JavaScriptModuleOrigin | undefined => {
|
||||
if (binding.directOrigins.length > 0)
|
||||
return binding.directOrigins.length === 1
|
||||
@@ -1172,13 +1181,14 @@ const bindingOrigin = (
|
||||
? electronRequireOrigin(initializer.node, state)?.origin
|
||||
: visited.has(alias.bindingId) ||
|
||||
exhausted ||
|
||||
!originAvailableAt(alias, source, state) ||
|
||||
[binding, alias].some(
|
||||
(hop) =>
|
||||
semanticBindingCanBeRebound(hop) &&
|
||||
semanticBindingMayHaveOpaqueEffect(hop, state),
|
||||
)
|
||||
? undefined
|
||||
: bindingOrigin(alias, state, new Set([...visited, binding.bindingId]));
|
||||
: bindingOrigin(alias, state, visited.add(binding.bindingId));
|
||||
const projection = initializer.projection;
|
||||
return origin === undefined ||
|
||||
!projection.every((key): key is string => typeof key === "string")
|
||||
|
||||
Reference in new issue
Block a user