Bug 1300550 - IonMonkey - Don't overflow BufferOffsets, r=sstangl
authorHannes Verschore <hv1989@gmail.com>
Fri, 28 Oct 2016 21:44:40 +0200
changeset 319981 683d731aad23ced97d7ba5f0e16400fc570a4454
parent 319980 d77c9965e9b287150fcc5fc23d386a9ade278bd2
child 319982 73aacf4a8f568cfd66a7a306cce0879bbdd5de5b
push id30882
push userryanvm@gmail.com
push dateSat, 29 Oct 2016 13:12:06 +0000
treeherdermozilla-central@16cdd6273c48 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstangl
bugs1300550
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1300550 - IonMonkey - Don't overflow BufferOffsets, r=sstangl
js/src/jit/arm/Assembler-arm.cpp
js/src/jit/arm64/vixl/MacroAssembler-vixl.h
js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
js/src/jit/shared/IonAssemblerBuffer.h
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -2192,17 +2192,22 @@ Assembler::as_BranchPool(uint32_t value,
     PoolHintPun php;
     php.phd.init(0, c, PoolHintData::PoolBranch, pc);
     BufferOffset ret = allocEntry(1, 1, (uint8_t*)&php.raw, (uint8_t*)&value, pe,
                                   /* markAsBranch = */ true, /* loadToPC = */ true);
     // If this label is already bound, then immediately replace the stub load
     // with a correct branch.
     if (label->bound()) {
         BufferOffset dest(label);
-        as_b(dest.diffB<BOffImm>(ret), c, ret);
+        BOffImm offset = dest.diffB<BOffImm>(ret);
+        if (offset.isInvalid()) {
+            m_buffer.fail_bail();
+            return ret;
+        }
+        as_b(offset, c, ret);
     } else if (!oom()) {
         label->use(ret.getOffset());
     }
 #ifdef JS_DISASM_ARM
     if (documentation)
         spewTarget(documentation);
 #endif
     return ret;
@@ -2380,16 +2385,18 @@ Assembler::as_bx(Register r, Condition c
     BufferOffset ret = writeInst(((int) c) | OpBx | r.code());
     return ret;
 }
 
 void
 Assembler::WritePoolGuard(BufferOffset branch, Instruction* dest, BufferOffset afterPool)
 {
     BOffImm off = afterPool.diffB<BOffImm>(branch);
+    if (off.isInvalid())
+        MOZ_CRASH("BOffImm invalid");
     *dest = InstBImm(off, Always);
 }
 
 // Branch can branch to an immediate *or* to a register.
 // Branches to immediates are pc relative, branches to registers are absolute.
 BufferOffset
 Assembler::as_b(BOffImm off, Condition c, Label* documentation)
 {
@@ -2482,17 +2489,23 @@ BufferOffset
 Assembler::as_bl(Label* l, Condition c)
 {
     if (l->bound()) {
         // Note only one instruction is emitted here, the NOP is overwritten.
         BufferOffset ret = allocBranchInst();
         if (oom())
             return BufferOffset();
 
-        as_bl(BufferOffset(l).diffB<BOffImm>(ret), c, ret);
+        BOffImm offset = BufferOffset(l).diffB<BOffImm>(ret);
+        if (offset.isInvalid()) {
+            m_buffer.fail_bail();
+            return BufferOffset();
+        }
+
+        as_bl(offset, c, ret);
 #ifdef JS_DISASM_ARM
         spewBranch(m_buffer.getInstOrNull(ret), l);
 #endif
         return ret;
     }
 
     if (oom())
         return BufferOffset();
@@ -2856,20 +2869,25 @@ Assembler::bind(Label* label, BufferOffs
         // want to bind to the location of the next instruction.
         BufferOffset dest = boff.assigned() ? boff : nextOffset();
         BufferOffset b(label);
         do {
             BufferOffset next;
             more = nextLink(b, &next);
             Instruction branch = *editSrc(b);
             Condition c = branch.extractCond();
+            BOffImm offset = dest.diffB<BOffImm>(b);
+            if (offset.isInvalid()) {
+                m_buffer.fail_bail();
+                return;
+            }
             if (branch.is<InstBImm>())
-                as_b(dest.diffB<BOffImm>(b), c, b);
+                as_b(offset, c, b);
             else if (branch.is<InstBLImm>())
-                as_bl(dest.diffB<BOffImm>(b), c, b);
+                as_bl(offset, c, b);
             else
                 MOZ_CRASH("crazy fixup!");
             b = next;
         } while (more);
     }
     label->bind(nextOffset().getOffset());
     MOZ_ASSERT(!oom());
 }
@@ -2902,17 +2920,23 @@ Assembler::bind(RepatchLabel* label)
         Instruction* branch = editSrc(branchOff);
         PoolHintPun p;
         p.raw = branch->encode();
         Condition cond;
         if (p.phd.isValidPoolHint())
             cond = p.phd.getCond();
         else
             cond = branch->extractCond();
-        as_b(dest.diffB<BOffImm>(branchOff), cond, branchOff);
+
+        BOffImm offset = dest.diffB<BOffImm>(branchOff);
+        if (offset.isInvalid()) {
+            m_buffer.fail_bail();
+            return;
+        }
+        as_b(offset, cond, branchOff);
     }
     label->bind(dest.getOffset());
 }
 
 void
 Assembler::retarget(Label* label, Label* target)
 {
 #ifdef JS_DISASM_ARM
--- a/js/src/jit/arm64/vixl/MacroAssembler-vixl.h
+++ b/js/src/jit/arm64/vixl/MacroAssembler-vixl.h
@@ -2302,17 +2302,17 @@ class MacroAssembler : public js::jit::A
   // to compute an intermediate address. The resulting MemOperand is only valid
   // as long as `scratch_scope` remains valid.
   MemOperand BaseMemOperandForLoadStoreCPURegList(
       const CPURegList& registers,
       const MemOperand& mem,
       UseScratchRegisterScope* scratch_scope);
 
   bool LabelIsOutOfRange(Label* label, ImmBranchType branch_type) {
-    return !Instruction::IsValidImmPCOffset(branch_type, nextOffset().diffB<int32_t>(label));
+    return !Instruction::IsValidImmPCOffset(branch_type, nextOffset().getOffset() - label->offset());
   }
 
   // The register to use as a stack pointer for stack operations.
   Register sp_;
 
   // Scratch registers available for use by the MacroAssembler.
   CPURegList tmp_list_;
   CPURegList fptmp_list_;
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
@@ -1579,19 +1579,20 @@ MacroAssembler::callWithPatch()
     return CodeOffset(currentOffset());
 }
 
 void
 MacroAssembler::patchCall(uint32_t callerOffset, uint32_t calleeOffset)
 {
     BufferOffset call(callerOffset - 7 * sizeof(uint32_t));
 
-    if (BOffImm16::IsInRange(BufferOffset(calleeOffset).diffB<int>(call))) {
+    BOffImm16 offset = BufferOffset(calleeOffset).diffB<BOffImm16>(call);
+    if (!offset.isInvalid()) {
         InstImm* bal = (InstImm*)editSrc(call);
-        bal->setBOffImm16(BufferOffset(calleeOffset).diffB<BOffImm16>(call));
+        bal->setBOffImm16(offset);
     } else {
         uint32_t u32Offset = callerOffset - 5 * sizeof(uint32_t);
         uint32_t* u32 = reinterpret_cast<uint32_t*>(editSrc(BufferOffset(u32Offset)));
         *u32 = calleeOffset - callerOffset;
     }
 }
 
 CodeOffset
--- a/js/src/jit/shared/IonAssemblerBuffer.h
+++ b/js/src/jit/shared/IonAssemblerBuffer.h
@@ -44,22 +44,26 @@ class BufferOffset
 
     // A BOffImm is a Branch Offset Immediate. It is an architecture-specific
     // structure that holds the immediate for a pc relative branch. diffB takes
     // the label for the destination of the branch, and encodes the immediate
     // for the branch. This will need to be fixed up later, since A pool may be
     // inserted between the branch and its destination.
     template <class BOffImm>
     BOffImm diffB(BufferOffset other) const {
+        if (!BOffImm::IsInRange(offset - other.offset))
+            return BOffImm();
         return BOffImm(offset - other.offset);
     }
 
     template <class BOffImm>
     BOffImm diffB(Label* other) const {
         MOZ_ASSERT(other->bound());
+        if (!BOffImm::IsInRange(offset - other->offset()))
+            return BOffImm();
         return BOffImm(offset - other->offset());
     }
 };
 
 inline bool
 operator<(BufferOffset a, BufferOffset b)
 {
     return a.getOffset() < b.getOffset();