Firefox · SpiderMonkey
CVE-2026-16369
Integer Overflow in SpiderMonkey
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
forjs/src/jit/SimpleAllocator.cpp |
modified |
Files Changed
js/src/jit/BacktrackingAllocator.cppjs/src/jit/BacktrackingAllocator.hjs/src/jit/LIR.hjs/src/jit/SimpleAllocator.cppjs/src/jit/SimpleAllocator.hjs/src/jit/StackSlotAllocator.h
Patch
diff --git a/js/src/jit/BacktrackingAllocator.cpp b/js/src/jit/BacktrackingAllocator.cpp
index 59d7c44564e..64e4d434d22 100644
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -2239,11 +2239,13 @@ void BacktrackingAllocator::tryMergeBundles(LiveBundle* bundle0,
}
// Helper for ::mergeAndQueueRegisters
-void BacktrackingAllocator::allocateStackDefinition(VirtualRegister& reg) {
+bool BacktrackingAllocator::allocateStackDefinition(VirtualRegister& reg) {
LInstruction* ins = reg.ins()->toInstruction();
if (reg.def()->type() == LDefinition::STACKRESULTS) {
LStackArea alloc(ins->toInstruction());
- stackSlotAllocator.allocateStackArea(&alloc);
+ if (!stackSlotAllocator.allocateStackArea(&alloc)) {
+ return false;
+ }
reg.def()->setOutput(alloc);
} else {
// Because the definitions are visited in order, the area has been allocated
@@ -2253,6 +2255,7 @@ void BacktrackingAllocator::allocateStackDefinition(VirtualRegister& reg) {
const LStackArea* areaAlloc = area.def()->output()->toStackArea();
reg.def()->setOutput(areaAlloc->resultAlloc(ins, reg.def()));
}
+ return true;
}
// Helper for ::mergeAndQueueRegisters
@@ -2481,8 +2484,9 @@ bool BacktrackingAllocator::mergeAndQueueRegisters() {
VirtualRegister& reg = vregs[i];
// Eagerly allocate stack result areas and their component stack results.
- if (reg.def() && reg.def()->policy() == LDefinition::STACK) {
- allocateStackDefinition(reg);
+ if (reg.def() && reg.def()->policy() == LDefinition::STACK &&
+ !allocateStackDefinition(reg)) {
+ return false;
}
for (VirtualRegister::RangeIterator iter(reg); iter; iter++) {
@@ -3970,7 +3974,10 @@ bool BacktrackingAllocator::pickStackSlot(SpillSet* spillSet) {
// We need a new physical stack slot.
LStackSlot::Width width = LStackSlot::width(type);
- uint32_t stackSlot = stackSlotAllocator.allocateSlot(width);
+ uint32_t stackSlot;
+ if (!stackSlotAllocator.allocateSlot(width, &stackSlot)) {
+ return false;
+ }
SpillSlot* spillSlot =
new (alloc().fallible()) SpillSlot(stackSlot, width, alloc().lifoAlloc());
diff --git a/js/src/jit/BacktrackingAllocator.h b/js/src/jit/BacktrackingAllocator.h
index 82b1955aa50..89d8e905185 100644
--- a/js/src/jit/BacktrackingAllocator.h
+++ b/js/src/jit/BacktrackingAllocator.h
@@ -867,7 +867,7 @@ class MOZ_STACK_CLASS BacktrackingAllocator : protected RegisterAllocator {
// Merging and queueing of LiveRange groups
void tryMergeBundles(LiveBundle* bundle0, LiveBundle* bundle1);
- void allocateStackDefinition(VirtualRegister& reg);
+ [[nodiscard]] bool allocateStackDefinition(VirtualRegister& reg);
[[nodiscard]] bool tryMergeReusedRegister(VirtualRegister& def,
VirtualRegister& input);
[[nodiscard]] bool mergeAndQueueRegisters();
diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h
index 3f4efeda795..cac3baca33e 100644
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -433,6 +433,9 @@ class LStackSlot : public LAllocation {
Width width() const { return Width(data_ & WIDTH_MASK); }
};
+ static constexpr uint32_t MAX_SLOT =
+ (uint64_t(1) << LAllocation::DATA_BITS) - 1;
+
explicit LStackSlot(SlotAndWidth slotAndWidth)
: LAllocation(STACK_SLOT, slotAndWidth.data()) {}
diff --git a/js/src/jit/SimpleAllocator.cpp b/js/src/jit/SimpleAllocator.cpp
index 1b668fec2f0..8f6b0d61827 100644
--- a/js/src/jit/SimpleAllocator.cpp
+++ b/js/src/jit/SimpleAllocator.cpp
@@ -383,16 +383,22 @@ void SimpleAllocator::removeAllocatedRegisterAtIndex(size_t index) {
}
}
-LAllocation SimpleAllocator::ensureStackLocation(uint32_t vregId) {
+bool SimpleAllocator::ensureStackLocation(uint32_t vregId, LAllocation* alloc) {
// Allocate a stack slot for this virtual register if needed.
VirtualRegister& vreg = vregs_[vregId];
if (vreg.hasStackLocation()) {
- return vreg.stackLocation();
+ *alloc = vreg.stackLocation();
+ return true;
}
LStackSlot::Width width = LStackSlot::width(vreg.def()->type());
- LStackSlot::SlotAndWidth slot(stackSlotAllocator_.allocateSlot(width), width);
+ uint32_t slotOffset;
+ if (!stackSlotAllocator_.allocateSlot(width, &slotOffset)) {
+ return false;
+ }
+ LStackSlot::SlotAndWidth slot(slotOffset, width);
vreg.setAllocatedStackSlot(slot);
- return LStackSlot(slot);
+ *alloc = LStackSlot(slot);
+ return true;
}
LAllocation SimpleAllocator::registerOrStackLocation(LInstruction* ins,
@@ -418,7 +424,10 @@ bool SimpleAllocator::spillRegister(LInstruction* ins,
}
// Allocate a new stack slot and insert a register => stack move.
LMoveGroup* input = getInputMoveGroup(ins);
- LAllocation dest = ensureStackLocation(allocated.vregId());
+ LAllocation dest;
+ if (!ensureStackLocation(allocated.vregId(), &dest)) {
+ return false;
+ }
return input->addAfter(LAllocation(allocated.reg()), dest,
vreg.def()->type());
}
@@ -469,7 +478,10 @@ bool SimpleAllocator::allocateForBlockEnd(LBlock* block, LInstruction* ins) {
LAllocation source =
registerOrStackLocation(ins, sourceVreg, /* trackRegUse = */ true);
- LAllocation dest = ensureStackLocation(destVreg);
+ LAllocation dest;
+ if (!ensureStackLocation(destVreg, &dest)) {
+ return false;
+ }
if (!group->add(source, dest, phi->getDef(0)->type())) {
return false;
}
@@ -795,7 +807,9 @@ bool SimpleAllocator::allocateForDefinition(uint32_t blockLastId,
MOZ_ASSERT(!isTemp);
if (def->type() == LDefinition::STACKRESULTS) {
LStackArea alloc(ins->toInstruction());
- stackSlotAllocator_.allocateStackArea(&alloc);
+ if (!stackSlotAllocator_.allocateStackArea(&alloc)) {
+ return false;
+ }
def->setOutput(alloc);
} else {
// Because the definitions are visited in order, the area has been
@@ -844,7 +858,10 @@ bool SimpleAllocator::allocateForInstruction(VirtualRegBitSet& liveGC,
LMoveGroup* moves = getInputMoveGroup(ins);
for (LDefinition* def : eagerSpillOutputs_) {
MOZ_ASSERT(!vregs_[def->virtualRegister()].hasStackLocation());
- LAllocation dest = ensureStackLocation(def->virtualRegister());
+ LAllocation dest;
+ if (!ensureStackLocation(def->virtualRegister(), &dest)) {
+ return false;
+ }
if (!moves->add(*def->output(), dest, def->type())) {
return false;
}
@@ -1182,7 +1199,11 @@ bool SimpleAllocator::allocateRegisters() {
LDefinition* def = phi->getDef(0);
uint32_t vregId = def->virtualRegister();
bool isGCType = vregs_[vregId].isGCType();
- def->setOutput(ensureStackLocation(vregId));
+ LAllocation defAlloc;
+ if (!ensureStackLocation(vregId, &defAlloc)) {
+ return false;
+ }
+ def->setOutput(defAlloc);
if (isGCType && !liveGC.insert(vregId)) {
return false;
}
diff --git a/js/src/jit/SimpleAllocator.h b/js/src/jit/SimpleAllocator.h
index dc282fd51e0..3aca8073908 100644
--- a/js/src/jit/SimpleAllocator.h
+++ b/js/src/jit/SimpleAllocator.h
@@ -323,7 +323,7 @@ class MOZ_STACK_CLASS SimpleAllocator : protected RegisterAllocator {
[[nodiscard]] bool allocateForBlockEnd(LBlock* block, LInstruction* ins);
- LAllocation ensureStackLocation(uint32_t vregId);
+ bool ensureStackLocation(uint32_t vregId, LAllocation* allocation);
LAllocation registerOrStackLocation(LInstruction* ins, uint32_t vregId,
bool trackRegUse);
diff --git a/js/src/jit/StackSlotAllocator.h b/js/src/jit/StackSlotAllocator.h
index ab666d9e53f..051c3d14e79 100644
--- a/js/src/jit/StackSlotAllocator.h
+++ b/js/src/jit/StackSlotAllocator.h
@@ -17,97 +17,165 @@ class StackSlotAllocator {
js::Vector<uint32_t, 4, SystemAllocPolicy> quadSlots;
uint32_t height_;
- void addAvailableSlot(uint32_t index) {
- // Ignoring OOM here (and below) is fine; it just means the stack slot
- // will be unused.
- (void)normalSlots.append(index);
- }
- void addAvailableDoubleSlot(uint32_t index) {
- (void)doubleSlots.append(index);
+ [[nodiscard]] bool incrementHeight(uint32_t amount) {
+ // See MaxBytes for why we don't need to check for overflow here.
Loading diff…
References
On This Page