tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 19ad14a754ef40186b044f8aa63ffdceda1ce1d9
parent 72f50387afb69407f4c14f3e4053a61226ce1aa0
Author: Iain Ireland <iireland@mozilla.com>
Date:   Mon,  6 Oct 2025 20:44:09 +0000

Bug 1991223: Handle arguments underflow in AllocateSpaceForApply r=jandem

Differential Revision: https://phabricator.services.mozilla.com/D267102

Diffstat:
Mjs/src/jit/CodeGenerator.cpp | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mjs/src/jit/CodeGenerator.h | 4+++-
2 files changed, 93 insertions(+), 28 deletions(-)

diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp @@ -6956,9 +6956,62 @@ void CodeGenerator::emitCallInvokeFunction(T* apply) { } // Do not bailout after the execution of this function since the stack no longer -// correspond to what is expected by the snapshots. -void CodeGenerator::emitAllocateSpaceForApply(Register argcreg, +// corresponds to what is expected by the snapshots. +template <typename T> +void CodeGenerator::emitAllocateSpaceForApply(T* apply, Register calleeReg, + Register argcreg, Register scratch) { + Label* oolRejoin = nullptr; + bool canUnderflow = + !apply->hasSingleTarget() || apply->getSingleTarget()->nargs() > 0; + + if (canUnderflow) { + auto* ool = new (alloc()) LambdaOutOfLineCode([=](OutOfLineCode& ool) { + // Align the JitFrameLayout on the JitStackAlignment by allocating + // callee->nargs() slots, possibly rounded up to the nearest odd + // number (see below). Leave callee->nargs() in `scratch` for the + // undef loop. + if (apply->hasSingleTarget()) { + uint32_t nargs = apply->getSingleTarget()->nargs(); + uint32_t numSlots = JitStackValueAlignment == 1 ? nargs : nargs | 1; + masm.subFromStackPtr(Imm32((numSlots) * sizeof(Value))); + masm.move32(Imm32(nargs), scratch); + } else { + // `scratch` contains callee->nargs() + if (JitStackValueAlignment > 1) { + masm.orPtr(Imm32(1), scratch); + } + masm.lshiftPtr(Imm32(ValueShift), scratch); + masm.subFromStackPtr(scratch); + masm.rshiftPtr(Imm32(ValueShift), scratch); + } + + // Count from callee->nargs() down to argc, storing undefined values. + Label loop; + masm.bind(&loop); + masm.sub32(Imm32(1), scratch); + masm.storeValue(UndefinedValue(), + BaseValueIndex(masm.getStackPointer(), scratch)); + masm.branch32(Assembler::Above, scratch, argcreg, &loop); + masm.jump(ool.rejoin()); + }); + addOutOfLineCode(ool, apply->mir()); + oolRejoin = ool->rejoin(); + + Label noUnderflow; + if (apply->hasSingleTarget()) { + masm.branch32(Assembler::AboveOrEqual, argcreg, + Imm32(apply->getSingleTarget()->nargs()), &noUnderflow); + } else { + masm.branchTestObjIsFunction(Assembler::NotEqual, calleeReg, scratch, + calleeReg, &noUnderflow); + masm.loadFunctionArgCount(calleeReg, scratch); + masm.branch32(Assembler::AboveOrEqual, argcreg, scratch, &noUnderflow); + } + masm.branchIfFunctionHasJitEntry(calleeReg, ool->entry()); + masm.bind(&noUnderflow); + } + // Use scratch register to calculate stack space (including padding). masm.movePtr(argcreg, scratch); @@ -7001,6 +7054,10 @@ void CodeGenerator::emitAllocateSpaceForApply(Register argcreg, masm.bind(&noPaddingNeeded); } #endif + + if (canUnderflow) { + masm.bind(oolRejoin); + } } // Do not bailout after the execution of this function since the stack no longer @@ -7123,13 +7180,14 @@ void CodeGenerator::emitPushArguments(Register argcreg, Register scratch, void CodeGenerator::emitPushArguments(LApplyArgsGeneric* apply) { // Holds the function nargs. + Register funcreg = ToRegister(apply->getFunction()); Register argcreg = ToRegister(apply->getArgc()); Register copyreg = ToRegister(apply->getTempObject()); Register scratch = ToRegister(apply->getTempForArgCopy()); uint32_t extraFormals = apply->numExtraFormals(); // Allocate space on the stack for arguments. - emitAllocateSpaceForApply(argcreg, scratch); + emitAllocateSpaceForApply(apply, funcreg, argcreg, scratch); emitPushArguments(argcreg, scratch, copyreg, extraFormals); @@ -7138,6 +7196,7 @@ void CodeGenerator::emitPushArguments(LApplyArgsGeneric* apply) { } void CodeGenerator::emitPushArguments(LApplyArgsObj* apply) { + Register function = ToRegister(apply->getFunction()); Register argsObj = ToRegister(apply->getArgsObj()); Register tmpArgc = ToRegister(apply->getTempObject()); Register scratch = ToRegister(apply->getTempForArgCopy()); @@ -7149,7 +7208,7 @@ void CodeGenerator::emitPushArguments(LApplyArgsObj* apply) { masm.loadArgumentsObjectLength(argsObj, tmpArgc); // Allocate space on the stack for arguments. - emitAllocateSpaceForApply(tmpArgc, scratch); + emitAllocateSpaceForApply(apply, function, tmpArgc, scratch); // Load arguments data. masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), @@ -7215,6 +7274,7 @@ void CodeGenerator::emitPushArrayAsArguments(Register tmpArgc, } void CodeGenerator::emitPushArguments(LApplyArrayGeneric* apply) { + Register function = ToRegister(apply->getFunction()); Register elements = ToRegister(apply->getElements()); Register tmpArgc = ToRegister(apply->getTempObject()); Register scratch = ToRegister(apply->getTempForArgCopy()); @@ -7230,7 +7290,7 @@ void CodeGenerator::emitPushArguments(LApplyArrayGeneric* apply) { masm.load32(Address(elements, ObjectElements::offsetOfLength()), tmpArgc); // Allocate space for the values. - emitAllocateSpaceForApply(tmpArgc, scratch); + emitAllocateSpaceForApply(apply, function, tmpArgc, scratch); // After this call "elements" has become "argc". size_t elementsOffset = 0; @@ -7362,33 +7422,36 @@ void CodeGenerator::emitApplyGeneric(T* apply) { masm.PushCalleeToken(calleereg, constructing); masm.PushFrameDescriptorForJitCall(FrameType::IonJS, argcreg, scratch); - Label underflow, rejoin; + // emitAllocateSpaceForApply handles arguments underflow for non-constructors + if (constructing) { + Label underflow, rejoin; - // Check whether the provided arguments satisfy target argc. - if (!apply->hasSingleTarget()) { - Register nformals = scratch; - masm.loadFunctionArgCount(calleereg, nformals); - masm.branch32(Assembler::Below, argcreg, nformals, &underflow); - } else { - masm.branch32(Assembler::Below, argcreg, - Imm32(apply->getSingleTarget()->nargs()), &underflow); - } + // Check whether the provided arguments satisfy target argc. + if (!apply->hasSingleTarget()) { + Register nformals = scratch; + masm.loadFunctionArgCount(calleereg, nformals); + masm.branch32(Assembler::Below, argcreg, nformals, &underflow); + } else { + masm.branch32(Assembler::Below, argcreg, + Imm32(apply->getSingleTarget()->nargs()), &underflow); + } - // Skip the construction of the rectifier frame because we have no - // underflow. - masm.jump(&rejoin); + // Skip the construction of the rectifier frame because we have no + // underflow. + masm.jump(&rejoin); - // Argument fixup needed. Get ready to call the argumentsRectifier. - { - masm.bind(&underflow); + // Argument fixup needed. Get ready to call the argumentsRectifier. + { + masm.bind(&underflow); - // Hardcode the address of the argumentsRectifier code. - TrampolinePtr argumentsRectifier = - gen->jitRuntime()->getArgumentsRectifier(); - masm.movePtr(argumentsRectifier, objreg); - } + // Hardcode the address of the argumentsRectifier code. + TrampolinePtr argumentsRectifier = + gen->jitRuntime()->getArgumentsRectifier(); + masm.movePtr(argumentsRectifier, objreg); + } - masm.bind(&rejoin); + masm.bind(&rejoin); + } // Finally call the function in objreg, as assigned by one of the paths // above. diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h @@ -176,7 +176,9 @@ class CodeGenerator final : public CodeGeneratorSpecific { void emitApplyGeneric(T* apply); template <typename T> void emitCallInvokeFunction(T* apply); - void emitAllocateSpaceForApply(Register argcreg, Register scratch); + template <typename T> + void emitAllocateSpaceForApply(T* apply, Register calleeReg, Register argcreg, + Register scratch); void emitAllocateSpaceForConstructAndPushNewTarget( Register argcreg, Register newTargetAndScratch); void emitCopyValuesForApply(Register argvSrcBase, Register argvIndex,