mirror of
https://github.com/denoland/deno.git
synced 2025-01-11 08:33:43 -05:00
fix(core): SafePromiseAll
to be unaffected by Array#@@iterator
(#17542)
This commit is contained in:
parent
bcb6ee9d08
commit
e5673f5ed8
6 changed files with 82 additions and 20 deletions
|
@ -851,10 +851,11 @@ Deno.test(
|
||||||
|
|
||||||
Deno.test(
|
Deno.test(
|
||||||
{ permissions: { read: true, run: true } },
|
{ permissions: { read: true, run: true } },
|
||||||
async function commandWithPromisePrototypeThenOverride() {
|
async function commandWithPrototypePollution() {
|
||||||
const originalThen = Promise.prototype.then;
|
const originalThen = Promise.prototype.then;
|
||||||
|
const originalSymbolIterator = Array.prototype[Symbol.iterator];
|
||||||
try {
|
try {
|
||||||
Promise.prototype.then = () => {
|
Promise.prototype.then = Array.prototype[Symbol.iterator] = () => {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
};
|
};
|
||||||
await new Deno.Command(Deno.execPath(), {
|
await new Deno.Command(Deno.execPath(), {
|
||||||
|
@ -862,6 +863,7 @@ Deno.test(
|
||||||
}).output();
|
}).output();
|
||||||
} finally {
|
} finally {
|
||||||
Promise.prototype.then = originalThen;
|
Promise.prototype.then = originalThen;
|
||||||
|
Array.prototype[Symbol.iterator] = originalSymbolIterator;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -2272,10 +2272,11 @@ Deno.test(
|
||||||
|
|
||||||
Deno.test(
|
Deno.test(
|
||||||
{ permissions: { net: true } },
|
{ permissions: { net: true } },
|
||||||
async function serveWithPromisePrototypeThenOverride() {
|
async function serveWithPrototypePollution() {
|
||||||
const originalThen = Promise.prototype.then;
|
const originalThen = Promise.prototype.then;
|
||||||
|
const originalSymbolIterator = Array.prototype[Symbol.iterator];
|
||||||
try {
|
try {
|
||||||
Promise.prototype.then = () => {
|
Promise.prototype.then = Array.prototype[Symbol.iterator] = () => {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
};
|
};
|
||||||
const ac = new AbortController();
|
const ac = new AbortController();
|
||||||
|
@ -2292,6 +2293,7 @@ Deno.test(
|
||||||
await server;
|
await server;
|
||||||
} finally {
|
} finally {
|
||||||
Promise.prototype.then = originalThen;
|
Promise.prototype.then = originalThen;
|
||||||
|
Array.prototype[Symbol.iterator] = originalSymbolIterator;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -329,10 +329,11 @@
|
||||||
return SafeIterator;
|
return SafeIterator;
|
||||||
};
|
};
|
||||||
|
|
||||||
primordials.SafeArrayIterator = createSafeIterator(
|
const SafeArrayIterator = createSafeIterator(
|
||||||
primordials.ArrayPrototypeSymbolIterator,
|
primordials.ArrayPrototypeSymbolIterator,
|
||||||
primordials.ArrayIteratorPrototypeNext,
|
primordials.ArrayIteratorPrototypeNext,
|
||||||
);
|
);
|
||||||
|
primordials.SafeArrayIterator = SafeArrayIterator;
|
||||||
primordials.SafeSetIterator = createSafeIterator(
|
primordials.SafeSetIterator = createSafeIterator(
|
||||||
primordials.SetPrototypeSymbolIterator,
|
primordials.SetPrototypeSymbolIterator,
|
||||||
primordials.SetIteratorPrototypeNext,
|
primordials.SetIteratorPrototypeNext,
|
||||||
|
@ -479,29 +480,80 @@
|
||||||
primordials.PromisePrototypeCatch = (thisPromise, onRejected) =>
|
primordials.PromisePrototypeCatch = (thisPromise, onRejected) =>
|
||||||
PromisePrototypeThen(thisPromise, undefined, onRejected);
|
PromisePrototypeThen(thisPromise, undefined, onRejected);
|
||||||
|
|
||||||
|
const arrayToSafePromiseIterable = (array) =>
|
||||||
|
new SafeArrayIterator(
|
||||||
|
ArrayPrototypeMap(
|
||||||
|
array,
|
||||||
|
(p) => {
|
||||||
|
if (ObjectPrototypeIsPrototypeOf(PromisePrototype, p)) {
|
||||||
|
return new SafePromise((c, d) => PromisePrototypeThen(p, c, d));
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Promise that is resolved with an array of results when all of the
|
* Creates a Promise that is resolved with an array of results when all of the
|
||||||
* provided Promises resolve, or rejected when any Promise is rejected.
|
* provided Promises resolve, or rejected when any Promise is rejected.
|
||||||
* @param {unknown[]} values An array of Promises.
|
* @template T
|
||||||
* @returns A new Promise.
|
* @param {Array<T | PromiseLike<T>>} values
|
||||||
|
* @returns {Promise<Awaited<T>[]>}
|
||||||
*/
|
*/
|
||||||
primordials.SafePromiseAll = (values) =>
|
primordials.SafePromiseAll = (values) =>
|
||||||
// Wrapping on a new Promise is necessary to not expose the SafePromise
|
// Wrapping on a new Promise is necessary to not expose the SafePromise
|
||||||
// prototype to user-land.
|
// prototype to user-land.
|
||||||
new Promise((a, b) =>
|
new Promise((a, b) =>
|
||||||
SafePromise.all(
|
SafePromise.all(arrayToSafePromiseIterable(values)).then(a, b)
|
||||||
ArrayPrototypeMap(
|
|
||||||
values,
|
|
||||||
(p) => {
|
|
||||||
if (ObjectPrototypeIsPrototypeOf(PromisePrototype, p)) {
|
|
||||||
return new SafePromise((c, d) => PromisePrototypeThen(p, c, d));
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
).then(a, b)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// NOTE: Uncomment the following functions when you need to use them
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Creates a Promise that is resolved with an array of results when all
|
||||||
|
// * of the provided Promises resolve or reject.
|
||||||
|
// * @template T
|
||||||
|
// * @param {Array<T | PromiseLike<T>>} values
|
||||||
|
// * @returns {Promise<PromiseSettledResult<T>[]>}
|
||||||
|
// */
|
||||||
|
// primordials.SafePromiseAllSettled = (values) =>
|
||||||
|
// // Wrapping on a new Promise is necessary to not expose the SafePromise
|
||||||
|
// // prototype to user-land.
|
||||||
|
// new Promise((a, b) =>
|
||||||
|
// SafePromise.allSettled(arrayToSafePromiseIterable(values)).then(a, b)
|
||||||
|
// );
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * The any function returns a promise that is fulfilled by the first given
|
||||||
|
// * promise to be fulfilled, or rejected with an AggregateError containing
|
||||||
|
// * an array of rejection reasons if all of the given promises are rejected.
|
||||||
|
// * It resolves all elements of the passed iterable to promises as it runs
|
||||||
|
// * this algorithm.
|
||||||
|
// * @template T
|
||||||
|
// * @param {T} values
|
||||||
|
// * @returns {Promise<Awaited<T[number]>>}
|
||||||
|
// */
|
||||||
|
// primordials.SafePromiseAny = (values) =>
|
||||||
|
// // Wrapping on a new Promise is necessary to not expose the SafePromise
|
||||||
|
// // prototype to user-land.
|
||||||
|
// new Promise((a, b) =>
|
||||||
|
// SafePromise.any(arrayToSafePromiseIterable(values)).then(a, b)
|
||||||
|
// );
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Creates a Promise that is resolved or rejected when any of the provided
|
||||||
|
// * Promises are resolved or rejected.
|
||||||
|
// * @template T
|
||||||
|
// * @param {T} values
|
||||||
|
// * @returns {Promise<Awaited<T[number]>>}
|
||||||
|
// */
|
||||||
|
// primordials.SafePromiseRace = (values) =>
|
||||||
|
// // Wrapping on a new Promise is necessary to not expose the SafePromise
|
||||||
|
// // prototype to user-land.
|
||||||
|
// new Promise((a, b) =>
|
||||||
|
// SafePromise.race(arrayToSafePromiseIterable(values)).then(a, b)
|
||||||
|
// );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches a callback that is invoked when the Promise is settled (fulfilled or
|
* Attaches a callback that is invoked when the Promise is settled (fulfilled or
|
||||||
* rejected). The resolved value cannot be modified from the callback.
|
* rejected). The resolved value cannot be modified from the callback.
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
PromisePrototypeThen,
|
PromisePrototypeThen,
|
||||||
RangeError,
|
RangeError,
|
||||||
ReferenceError,
|
ReferenceError,
|
||||||
|
SafeArrayIterator,
|
||||||
SafePromisePrototypeFinally,
|
SafePromisePrototypeFinally,
|
||||||
setQueueMicrotask,
|
setQueueMicrotask,
|
||||||
StringPrototypeSlice,
|
StringPrototypeSlice,
|
||||||
|
@ -198,7 +199,7 @@
|
||||||
const id = rollPromiseId();
|
const id = rollPromiseId();
|
||||||
let promise = PromisePrototypeThen(setPromise(id), unwrapOpResult);
|
let promise = PromisePrototypeThen(setPromise(id), unwrapOpResult);
|
||||||
try {
|
try {
|
||||||
ops[name](id, ...args);
|
ops[name](id, ...new SafeArrayIterator(args));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Cleanup the just-created promise
|
// Cleanup the just-created promise
|
||||||
getPromise(id);
|
getPromise(id);
|
||||||
|
|
4
core/internal.d.ts
vendored
4
core/internal.d.ts
vendored
|
@ -75,6 +75,10 @@ declare namespace __bootstrap {
|
||||||
typeof globalThis.FinalizationRegistry;
|
typeof globalThis.FinalizationRegistry;
|
||||||
export const SafeWeakRef: typeof globalThis.WeakRef;
|
export const SafeWeakRef: typeof globalThis.WeakRef;
|
||||||
export const SafePromiseAll: typeof Promise.all;
|
export const SafePromiseAll: typeof Promise.all;
|
||||||
|
// NOTE: Uncomment the following functions when you need to use them
|
||||||
|
// export const SafePromiseAllSettled: typeof Promise.allSettled;
|
||||||
|
// export const SafePromiseAny: typeof Promise.any;
|
||||||
|
// export const SafePromiseRace: typeof Promise.race;
|
||||||
export const SafePromisePrototypeFinally: UncurryThis<
|
export const SafePromisePrototypeFinally: UncurryThis<
|
||||||
Promise.prototype.finally
|
Promise.prototype.finally
|
||||||
>;
|
>;
|
||||||
|
|
|
@ -510,7 +510,8 @@ function buildCaseInsensitiveCommaValueFinder(checkText) {
|
||||||
|
|
||||||
/** @param value {string} */
|
/** @param value {string} */
|
||||||
function hasWord(value) {
|
function hasWord(value) {
|
||||||
for (const [cLower, cUpper] of charCodes) {
|
for (let j = 0; j < charCodes.length; ++j) {
|
||||||
|
const { 0: cLower, 1: cUpper } = charCodes[j];
|
||||||
if (cLower === char || cUpper === char) {
|
if (cLower === char || cUpper === char) {
|
||||||
char = StringPrototypeCharCodeAt(value, ++i);
|
char = StringPrototypeCharCodeAt(value, ++i);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue