hphp/runtime/vm/verifier/check_func.cpp
/**
 * Scan instructions in the given section to find valid instruction
 * boundaries, and check that branches a) land on valid boundaries,
 * b) do not escape the section.
 */
Scan instructions in the given section to find valid instruction
boundaries, and check that branches a) land on valid boundaries,
b) do not escape the section.
Scan instructions in the given section to find valid instruction boundaries and check that branches a ) land on valid boundaries b ) do not escape the section .
bool FuncChecker::checkSection(bool is_main, const char* name, Offset base,
                               Offset past) {
  bool ok = true;
  typedef std::list<PC> BranchList;
  BranchList branches;
  PC bc = unit()->entry();
  for (InstrRange i(at(base), at(past)); !i.empty();) {
    if (!checkImmediates(name, (Op*)i.front())) return false;
    PC pc = i.popFront();
    m_instrs.set(offset(pc) - m_func->base());
    if (isSwitch(toOp(*pc)) ||
        instrJumpTarget((Op*)bc, offset(pc)) != InvalidAbsoluteOffset) {
      if (toOp(*pc) == OpSwitch && getImm((Op*)pc, 2).u_IVA != 0) {
        int64_t switchBase = getImm((Op*)pc, 1).u_I64A;
        int32_t len = getImmVector((Op*)pc).size();
        if (len <= 2) {
          error("Bounded switch must have a vector of length > 2 [%d:%d]\n",
                base, past);
        }
        if (switchBase > std::numeric_limits<int64_t>::max() - len + 2) {
          error("Overflow in Switch bounds [%d:%d]\n", base, past);
        }
      } else if (toOp(*pc) == OpSSwitch) {
        foreachSwitchString((Opcode*)pc, [&](Id& id) {
          ok &= checkString(pc, id);
        });
      }
      branches.push_back(pc);
    }
    if (i.empty()) {
      if (offset(pc + instrLen((Op*)pc)) != past) {
        error("Last instruction in %s at %d overflows [%d:%d]\n",
               name, offset(pc), base, past);
        ok = false;
      }
      if (!isTF(pc)) {
        error("Last instruction in %s is not teriminal %d:%s\n",
               name, offset(pc), instrToString((Op*)pc, unit()).c_str());
        ok = false;
      } else {
        if (isRet(pc) && !is_main) {
          error("Ret* may not appear in %s\n", name);
          ok = false;
        } else if (Op(*pc) == OpUnwind && is_main) {
          error("Unwind may not appear in %s\n", name);
          ok = false;
        }
      }
    }
  }
  for (Range<BranchList> i(branches); !i.empty();) {
    PC branch = i.popFront();
    if (isSwitch(*branch)) {
      foreachSwitchTarget((Op*)branch, [&](Offset& o) {
        if (offset(branch + o) != -1) {
          ok &= checkOffset("switch target", offset(branch + o),
                            name, base, past);
        }
      });
    } else {
      Offset target = instrJumpTarget((Op*)bc, offset(branch));
      ok &= checkOffset("branch target", target, name, base, past);
    }
  }
  return ok;
}
bool FuncChecker :: checkSection ( bool is_main , const char * name , Offset base , Offset past ) { bool ok = true ; typedef std :: list < PC > BranchList ; BranchList branches ; PC bc = unit ( ) -> entry ( ) ; for ( InstrRange i ( at ( base ) , at ( past ) ) ; ! i . empty ( ) ; ) { if ( ! checkImmediates ( name , ( Op * ) i . front ( ) ) ) return false ; PC pc = i . popFront ( ) ; m_instrs . set ( offset ( pc ) - m_func -> base ( ) ) ; if ( isSwitch ( toOp ( * pc ) ) || instrJumpTarget ( ( Op * ) bc , offset ( pc ) ) != InvalidAbsoluteOffset ) { if ( toOp ( * pc ) == OpSwitch && getImm ( ( Op * ) pc , 2 ) . u_IVA != 0 ) { int64_t switchBase = getImm ( ( Op * ) pc , 1 ) . u_I64A ; int32_t len = getImmVector ( ( Op * ) pc ) . size ( ) ; if ( len <= 2 ) { error ( " \n " , base , past ) ; } if ( switchBase > std :: numeric_limits < int64_t > :: max ( ) - len + 2 ) { error ( " \n " , base , past ) ; } } else if ( toOp ( * pc ) == OpSSwitch ) { foreachSwitchString ( ( Opcode * ) pc , [ & ] ( Id & id ) { ok &= checkString ( pc , id ) ; } ) ; } branches . push_back ( pc ) ; } if ( i . empty ( ) ) { if ( offset ( pc + instrLen ( ( Op * ) pc ) ) != past ) { error ( " \n " , name , offset ( pc ) , base , past ) ; ok = false ; } if ( ! isTF ( pc ) ) { error ( " \n " , name , offset ( pc ) , instrToString ( ( Op * ) pc , unit ( ) ) . c_str ( ) ) ; ok = false ; } else { if ( isRet ( pc ) && ! is_main ) { error ( " \n " , name ) ; ok = false ; } else if ( Op ( * pc ) == OpUnwind && is_main ) { error ( " \n " , name ) ; ok = false ; } } } } for ( Range < BranchList > i ( branches ) ; ! i . empty ( ) ; ) { PC branch = i . popFront ( ) ; if ( isSwitch ( * branch ) ) { foreachSwitchTarget ( ( Op * ) branch , [ & ] ( Offset & o ) { if ( offset ( branch + o ) != -1 ) { ok &= checkOffset ( " " , offset ( branch + o ) , name , base , past ) ; } } ) ; } else { Offset target = instrJumpTarget ( ( Op * ) bc , offset ( branch ) ) ; ok &= checkOffset ( " " , target , name , base , past ) ; } } return ok ; }
Scan instructions in the given section to find valid instruction
 boundaries, and check that branches a) land on valid boundaries,
 b) do not escape the section.
Scan instructions in the given section to find valid instruction boundaries and check that branches a ) land on valid boundaries b ) do not escape the section .
// Find instruction boundaries and branch instructions. // Check each branch target lands on a valid instruction boundary // within this region. // TODO(#2464197): dce breaks switch for verify