Skip to content
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

fix(workflow): Fix multiple context leaks in reuseV8Context executor #1519

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 30 additions & 16 deletions packages/common/src/type-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,23 +219,37 @@ export function SymbolBasedInstanceOfError<E extends Error>(markerName: string):
};
}

// Thanks MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
export function deepFreeze<T>(object: T): T {
// Retrieve the property names defined on object
const propNames = Object.getOwnPropertyNames(object);

// Freeze properties before freezing self
for (const name of propNames) {
const value = (object as any)[name];

if (value && typeof value === 'object') {
try {
deepFreeze(value);
} catch (_err) {
// This is okay, there are some typed arrays that cannot be frozen (encodingKeys)
// This implementation is based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze.
//
// Note that there are limits to this approach, as traversing using getOwnPropertyXxx doesn't allow
// reaching variables defined in internal scopes. That notably means that Map and Set classes,
// are not frozen. It is simply impossible to cover all potential cases.
//
// We also do not attempt to visit the prototype chain, as this would make it much harder to load
// polyfills, and it is extremely unlikely anyway that one would modify the prototype of a built-in
// object in a way that would have undesirable consequences (i.e. a polyfill function may actually
// leak to another workflow context, but it wouldn't carry anything Workflow specific).
export function deepFreeze<T>(object: T, visited = new WeakSet<any>()): T {
if (object == null || visited.has(object) || (typeof object !== 'object' && typeof object !== 'function'))
return object;
visited.add(object);
if (Object.isFrozen(object)) return object;

if (typeof object === 'object') {
// Retrieve the property names defined on object
const propNames = [...Object.getOwnPropertyNames(object), ...Object.getOwnPropertySymbols(object)];

// Freeze properties before freezing self
for (const name of propNames) {
const value = (object as any)[name];

if (value && (typeof value === 'object' || typeof value === 'function')) {
try {
deepFreeze(value, visited);
} catch (_err) {
// This is okay, for various reasons, some objects can't be frozen, e.g. Uint8Array.
}
}
} else if (typeof value === 'function') {
Object.freeze(value);
}
}

Expand Down
Loading
Loading