Bug 1300550 - IonMonkey - Don't overflow BufferOffsets, r=sstangl
authorHannes Verschore <hv1989@gmail.com>
Fri, 28 Oct 2016 21:44:40 +0200
changeset 320075 683d731aad23ced97d7ba5f0e16400fc570a4454
parent 320074 d77c9965e9b287150fcc5fc23d386a9ade278bd2
child 320076 73aacf4a8f568cfd66a7a306cce0879bbdd5de5b
push id20749
push userryanvm@gmail.com
push dateSat, 29 Oct 2016 13:21:21 +0000
treeherderfx-team@1b170b39ed6b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstangl
bugs1300550
milestone52.0a1
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();