Files
rea/src/composition/binary.ts
T
morluto 9512a80804 feat(process): make the regex worker heap request configurable (#6301)
* feat(process): make the regex worker heap request configurable

REA_REGEX_WORKER_HEAP_REQUEST_MIB keeps the 128 MiB default and refuses
values outside 8 to 16384 MiB. A positive Node --max-old-space-size still
overrides the request and is not clamped by the setting.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(process): set the regex worker heap floor to the measured startup bound

On Node 22.23.4 a 5 MiB old-generation request aborts the regex worker
during startup, and 6 MiB starts it and returns a match. The setting floor
is that measured bound.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(process): raise the regex worker heap floor to 7 MiB

6 MiB passes configuration but returns ERR_WORKER_OUT_OF_MEMORY for a
trivial match on supported Linux Node 24 and Node 26.0.0. 7 MiB returned
that match on the measured 22, 24, and 26 lines. A clean-process test
runs the production worker at the floor.

Co-authored-by: morluto <morluto@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
2026-10-22 23:43:13 +08:00

169 lines
6.0 KiB
TypeScript

import { isAppleDispatchMetadataTarget } from "../domain/native/objcSwiftMetadata.js";
import { snapshotEnvironment } from "../process/snapshotEnvironment.js";
import type { AppConfig } from "../config/types.js";
import type { BinarySession } from "../application/binary/BinarySession.js";
import { HopperProvider } from "../hopper/HopperProvider.js";
import { GhidraProvider } from "../ghidra/GhidraProvider.js";
import { IdaProvider } from "../ida/IdaProvider.js";
import { KunaProvider } from "../kuna/KunaProvider.js";
import type { Logger } from "pino";
import { auxiliaryAnalysisProviderDeclarations } from "./auxiliaryAnalysisProviders.js";
import { AnalysisProviderRegistry } from "../application/binary/AnalysisProviderRegistry.js";
import { composeBinarySession } from "../application/binary/BinarySessionComposition.js";
import { LazyAnalysisProvider } from "../application/binary/LazyAnalysisProvider.js";
import { ManagedStaticProvider } from "../dotnet/ManagedStaticProvider.js";
import {
BUNDLE_ARTIFACT_RESOURCE_OPERATIONS,
BUNDLE_NATIVE_RESOURCE_OPERATIONS,
combineBundleResourceClients,
} from "../application/binary/BundleResourceSession.js";
/**
* Compose the target-switching runtime shared directly by CLI and MCP adapters.
* This is the sole production wiring point, so both adapters share identical
* provider selection, profile, lifecycle, and Evidence semantics.
*/
export const createBinarySession = (
config: AppConfig,
logger: Logger,
selectedEnvironment: Readonly<NodeJS.ProcessEnv>,
): BinarySession =>
composeDeepBinarySession(config, logger, selectedEnvironment);
/** Prefer byte-backed dispatch inspection while retaining deep symbol fallback. */
export const createNativeDispatchBinarySession = (
config: AppConfig,
logger: Logger,
selectedEnvironment: Readonly<NodeJS.ProcessEnv>,
): BinarySession =>
composeDeepBinarySession(
config,
logger,
selectedEnvironment,
"inspect_native_dispatch_metadata",
);
const composeDeepBinarySession = (
config: AppConfig,
logger: Logger,
selectedEnvironment: Readonly<NodeJS.ProcessEnv>,
inspection?: "inspect_native_dispatch_metadata",
): BinarySession => {
const environment = snapshotEnvironment(selectedEnvironment);
const hopper = new HopperProvider(config, logger, environment);
const ghidra = new GhidraProvider(config, logger, environment);
const ida = new IdaProvider(config, environment);
const kuna = new KunaProvider(environment, {
regexMatchingDeadline: config.regexMatchingDeadline,
regexWorkerHeapRequest: config.regexWorkerHeapRequest,
});
const auxiliaryDeclarations =
auxiliaryAnalysisProviderDeclarations(environment);
const nativeInspectionAvailable =
inspection !== undefined &&
auxiliaryDeclarations.some(({ capabilities }) =>
capabilities.some(
({ operation, available }) => operation === inspection && available,
),
);
return composeBinarySession(
new AnalysisProviderRegistry(
[hopper, ghidra, ida, kuna],
config.analysisProvider,
nativeInspectionAvailable ? isAppleDispatchMetadataTarget : undefined,
),
auxiliaryDeclarations.map(
(declaration) => new LazyAnalysisProvider(declaration),
),
createBundleResourceFactory(environment, process.platform),
);
};
const createBundleResourceFactory = (
environment: Readonly<NodeJS.ProcessEnv>,
platform: NodeJS.Platform,
) => {
return {
createClient: async (
root: import("../application/AppBundleExecutable.js").ResolvedAppBundleResourceRoot,
) => {
const [{ ArtifactProvider }, { NativeMacOSProvider }] = await Promise.all(
[
import("../artifacts/ArtifactProvider.js"),
import("../native/NativeMacOSProvider.js"),
],
);
const artifact = new ArtifactProvider(environment, platform);
const native = new NativeMacOSProvider(environment, undefined, platform);
const capabilities = [
...artifact
.capabilities()
.filter(({ operation }) =>
BUNDLE_ARTIFACT_RESOURCE_OPERATIONS.has(operation),
),
...native
.capabilities()
.filter(({ operation }) =>
BUNDLE_NATIVE_RESOURCE_OPERATIONS.has(operation),
),
];
return {
client: combineBundleResourceClients(
artifact.createBundleResourceClient(root),
native.createBundleResourceClient(root),
),
capabilities,
};
},
};
};
/** Compose an execution-free managed session without native provider selection. */
export const createManagedBinarySession = (): BinarySession =>
composeBinarySession(new AnalysisProviderRegistry([]), [
new ManagedStaticProvider(),
]);
/** Compose the artifact operations without candidates for deep analysis engines. */
export const createArtifactBinarySession = (
selectedEnvironment: Readonly<NodeJS.ProcessEnv>,
platform: NodeJS.Platform = process.platform,
): Promise<BinarySession> =>
import("../artifacts/ArtifactProvider.js").then(({ ArtifactProvider }) =>
composeBinarySession(
new AnalysisProviderRegistry([]),
[
new ArtifactProvider(
snapshotEnvironment(selectedEnvironment, platform),
platform,
),
],
createBundleResourceFactory(
snapshotEnvironment(selectedEnvironment, platform),
platform,
),
),
);
/** Compose native inspection utilities without candidates for deep analysis. */
export const createNativeBinarySession = (
selectedEnvironment: Readonly<NodeJS.ProcessEnv>,
platform: NodeJS.Platform = process.platform,
): Promise<BinarySession> =>
import("../native/NativeMacOSProvider.js").then(({ NativeMacOSProvider }) =>
composeBinarySession(
new AnalysisProviderRegistry([]),
[
new NativeMacOSProvider(
snapshotEnvironment(selectedEnvironment, platform),
undefined,
platform,
),
],
createBundleResourceFactory(
snapshotEnvironment(selectedEnvironment, platform),
platform,
),
),
);