Ejemplo n.º 1
0
UnwindAction checkHandlers(const EHEnt* eh,
                           const ActRec* const fp,
                           PC& pc,
                           Fault& fault) {
  auto const func = fp->m_func;
  FTRACE(1, "checkHandlers: func {} ({})\n",
         func->fullName()->data(),
         func->unit()->filepath()->data());

  // Always blindly propagate on fatal exception since those are
  // unrecoverable anyway.
  if (fault.m_faultType == Fault::Type::CppException) {
    return UnwindAction::Propagate;
  }

  for (int i = 0;; ++i) {
    // Skip the initial m_handledCount - 1 handlers that were
    // considered before.
    if (fault.m_handledCount <= i) {
      fault.m_handledCount++;
      switch (eh->m_type) {
      case EHEnt::Type::Fault:
        FTRACE(1, "checkHandlers: entering fault at {}: save {}\n",
               eh->m_fault,
               func->unit()->offsetOf(pc));
        pc = func->unit()->entry() + eh->m_fault;
        DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook());
        return UnwindAction::ResumeVM;
      case EHEnt::Type::Catch:
        // Note: we skip catch clauses if we have a pending C++ exception
        // as part of our efforts to avoid running more PHP code in the
        // face of such exceptions.
        if (fault.m_faultType == Fault::Type::UserException &&
            ThreadInfo::s_threadInfo->m_pendingException == nullptr) {
          auto const obj = fault.m_userException;
          for (auto& idOff : eh->m_catches) {
            FTRACE(1, "checkHandlers: catch candidate {}\n", idOff.second);
            auto handler = func->unit()->at(idOff.second);
            auto const cls = Unit::lookupClass(
              func->unit()->lookupNamedEntityId(idOff.first)
            );
            if (!cls || !obj->instanceof(cls)) continue;

            FTRACE(1, "checkHandlers: entering catch at {}\n", idOff.second);
            pc = handler;
            DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook());
            return UnwindAction::ResumeVM;
          }
        }
        break;
      }
    }
    if (eh->m_parentIndex != -1) {
      eh = &func->ehtab()[eh->m_parentIndex];
    } else {
      break;
    }
  }
  return UnwindAction::Propagate;
}
Ejemplo n.º 2
0
UnwindAction checkHandlers(const EHEnt* eh,
                           const ActRec* const fp,
                           PC& pc,
                           Fault& fault) {
  auto const func = fp->m_func;
  ITRACE(1, "checkHandlers: func {} ({})\n",
         func->fullName()->data(),
         func->unit()->filepath()->data());

  for (int i = 0;; ++i) {
    // Skip the initial m_handledCount - 1 handlers that were
    // considered before.
    if (fault.m_handledCount <= i) {
      fault.m_handledCount++;
      switch (eh->m_type) {
      case EHEnt::Type::Fault:
        ITRACE(1, "checkHandlers: entering fault at {}: save {}\n",
               eh->m_handler,
               func->unit()->offsetOf(pc));
        pc = func->unit()->at(eh->m_handler);
        DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook());
        return UnwindAction::ResumeVM;
      case EHEnt::Type::Catch:
        ITRACE(1, "checkHandlers: entering catch at {}\n", eh->m_handler);
        pc = func->unit()->at(eh->m_handler);
        DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook());
        return UnwindAction::ResumeVM;
      }
    }
    if (eh->m_parentIndex != -1) {
      eh = &func->ehtab()[eh->m_parentIndex];
    } else {
      break;
    }
  }
  return UnwindAction::Propagate;
}
Ejemplo n.º 3
0
UnwindAction checkHandlers(const EHEnt* eh,
                           const ActRec* const fp,
                           PC& pc,
                           Fault& fault) {
  auto const func = fp->m_func;

  FTRACE(1, "checkHandlers: func {} ({})\n",
         func->fullName()->data(),
         func->unit()->filepath()->data());

  /*
   * This code is repeatedly called with the same offset when an
   * exception is raised and rethrown by fault handlers.  The
   * `faultNest' iterator is here to skip the EHEnt handlers that have
   * already been run for this in-flight exception.
   */
  int faultNest = 0;
  for (;;) {
    assert(faultNest <= fault.m_handledCount);
    if (faultNest == fault.m_handledCount) {
      ++fault.m_handledCount;

      switch (eh->m_type) {
      case EHEnt::Type::Fault:
        FTRACE(1, "checkHandlers: entering fault at {}: save {}\n",
               eh->m_fault,
               func->unit()->offsetOf(pc));
        fault.m_savedRaiseOffset = func->unit()->offsetOf(pc);
        pc = func->unit()->entry() + eh->m_fault;
        DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook());
        return UnwindAction::ResumeVM;
      case EHEnt::Type::Catch:
        // Note: we skip catch clauses if we have a pending C++ exception
        // as part of our efforts to avoid running more PHP code in the
        // face of such exceptions.
        if (fault.m_faultType == Fault::Type::UserException &&
            ThreadInfo::s_threadInfo->m_pendingException == nullptr) {
          auto const obj = fault.m_userException;
          for (auto& idOff : eh->m_catches) {
            FTRACE(1, "checkHandlers: catch candidate {}\n", idOff.second);
            auto handler = func->unit()->at(idOff.second);
            auto const cls = Unit::lookupClass(
              func->unit()->lookupNamedEntityId(idOff.first)
            );
            if (!cls || !obj->instanceof(cls)) continue;

            FTRACE(1, "checkHandlers: entering catch at {}\n", idOff.second);
            pc = handler;
            DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook());
            return UnwindAction::ResumeVM;
          }
        }
        break;
      }
    }

    if (eh->m_parentIndex != -1) {
      eh = &func->ehtab()[eh->m_parentIndex];
    } else {
      break;
    }
    ++faultNest;
  }

  return UnwindAction::Propagate;
}