Example #1
0
trie_tree* trie_tree_create_end()
{
  assert(be_creating);
  assert(!be_inserting);
  trie_tree* tree = (trie_tree*)malloc(sizeof(trie_tree));
  init_array(&tree->node_array, sizeof(trie_node));
  init_array(&successor_array, sizeof(trie_successor));
  append_array(&tree->node_array, 2);
  memset(get_array_elem(&tree->node_array, 0), 0, sizeof(trie_node)*2);
  trie_node* head_node = (trie_node*)get_array_elem(&tree->node_array, HEAD_INDEX);
  head_node->check = HEAD_CHECK;
  head_node->base = HEAD_INDEX;
  for(int input_index = 0; input_index<input_cache.len; input_index++)
  {
    int prefix_index, node_index, base_index;
    trie_input* input_node = (trie_input*)get_array_elem(&input_cache, input_index);
    while( find_prefix(tree, input_node->str, &prefix_index, &node_index) )
    {
      get_all_successors(input_node->str, prefix_index, input_index);
      base_index = find_base_index_by_successors(tree, node_index);
      insert_successors(tree, base_index, node_index);
    }
    mark_word_node(tree, node_index);
  }
  empty_array(&input_cache);
  empty_array(&successor_array);
  be_creating = false;
  return tree;
}
Example #2
0
void trie_tree_insert_end(trie_tree* tree)
{
  assert(!be_creating);
  assert(be_inserting);
  init_array(&successor_array, sizeof(trie_successor));
  for(int input_index = 0; input_index<input_cache.len; input_index++)
  {
    int prefix_index, node_index;
    trie_input* input_node = (trie_input*)get_array_elem(&input_cache, input_index);
    while( find_prefix(tree, input_node->str, &prefix_index, &node_index) )
    {
      int base_index = abs(((trie_node*)get_array_elem(&tree->node_array, node_index))->base);
      get_all_successors(input_node->str, prefix_index, input_index);
      delete_existing_successors(tree, node_index);
      if(base_index == node_index || !check_insert_successors(tree, node_index) )
      {
        reset_successors(tree, node_index);
        base_index = find_base_index_by_successors(tree, node_index);
      }
      insert_successors(tree, base_index, node_index);
    }
    mark_word_node(tree, node_index);
  }
  print_node(tree, 1, 0);
  empty_array(&input_cache);
  empty_array(&successor_array);
  be_inserting = false;
}
Example #3
0
Array HHVM_FUNCTION(heapgraph_node_in_edges,
  const Resource& resource,
  int64_t index
) {
  auto hgptr = get_valid_heapgraph_context_resource(resource, __FUNCTION__);
  if (!hgptr) return empty_array();
  if (index < 0 || index >= (hgptr->hg.nodes.size())) return empty_array();
  Array result;
  hgptr->hg.eachPredPtr(index, [&](int ptr) {
    result.append(createPhpEdge(hgptr, ptr));
  });
  return result;
}
Example #4
0
void AsioSession::onIOWaitExit() {
  runCallback(
    m_onIOWaitExitCallback,
    empty_array(),
    "WaitHandle::onIOWaitExit"
  );
}
Example #5
0
void AsioSession::onIOWaitEnter() {
  runCallback(
    m_onIOWaitEnterCallback,
    empty_array(),
    "WaitHandle::onIOWaitEnter"
  );
}
Example #6
0
Array Variant::toArrayHelper() const {
    switch (m_type) {
    case KindOfUninit:
    case KindOfNull:
        return empty_array();
    case KindOfBoolean:
        return Array::Create(*this);
    case KindOfInt64:
        return Array::Create(m_data.num);
    case KindOfDouble:
        return Array::Create(*this);
    case KindOfStaticString:
    case KindOfString:
        return Array::Create(Variant{m_data.pstr});
    case KindOfPersistentArray:
    case KindOfArray:
        return Array(m_data.parr);
    case KindOfObject:
        return m_data.pobj->toArray();
    case KindOfResource:
        return m_data.pres->data()->o_toArray();
    case KindOfRef:
        return m_data.pref->var()->toArray();
    case KindOfClass:
        break;
    }
    not_reached();
}
Array c_WaitableWaitHandle::getDependencyStack() {
  if (isFinished()) return empty_array();
  Array result = Array::Create();
  hphp_hash_set<c_WaitableWaitHandle*> visited;
  auto current_handle = this;
  auto session = AsioSession::Get();
  while (current_handle != nullptr) {
    result.append(Variant{current_handle});
    visited.insert(current_handle);
    auto context_idx = current_handle->getContextIdx();

    // 1. find parent in the same context
    auto p = current_handle->getParentChain().firstInContext(context_idx);
    if (p && visited.find(p) == visited.end()) {
      current_handle = p;
      continue;
    }

    // 2. cross the context boundary
    auto context = session->getContext(context_idx);
    if (!context) {
      break;
    }
    current_handle = c_ResumableWaitHandle::getRunning(context->getSavedFP());
    auto target_context_idx =
      current_handle ? current_handle->getContextIdx() : 0;
    while (context_idx > target_context_idx) {
      --context_idx;
      result.append(null_object);
    }
  }
  return result;
}
Array HHVM_FUNCTION(stream_get_filters) {
  auto filters = s_stream_user_filters.get()->m_registeredFilters;
  if (UNLIKELY(filters.isNull())) {
    return empty_array();
  }
  return array_keys_helper(filters.filtersAsArray()).toArray();
}
Example #9
0
static Array HHVM_FUNCTION(xenon_get_data, void) {
  if (RuntimeOption::XenonForceAlwaysOn ||
      RuntimeOption::XenonPeriodSeconds > 0) {
    TRACE(1, "xenon_get_data\n");
    return s_xenonData->createResponse();
  }
  return empty_array();
}
Example #10
0
Array c_WaitableWaitHandle::t_getparents() {
  // no parent data available if finished
  if (isFinished()) {
    return empty_array();
  }

  return getParentChain().toArray();
}
Example #11
0
Array HHVM_FUNCTION(apache_response_headers) {
  Transport *transport = g_context->getTransport();
  if (transport) {
    HeaderMap headers;
    transport->getResponseHeaders(headers);
    return get_headers(headers);
  }
  return empty_array();
}
Example #12
0
Array HHVM_FUNCTION(get_headers_secure) {
  Transport *transport = g_context->getTransport();
  if (transport) {
    HeaderMap headers;
    transport->getHeaders(headers);
    return get_headers(headers, true);
  }
  return empty_array();
}
Example #13
0
 Array getVar(int64_t type) {
   switch (type) {
     case k_INPUT_GET: return m_GET;
     case k_INPUT_POST: return m_POST;
     case k_INPUT_COOKIE: return m_COOKIE;
     case k_INPUT_SERVER: return m_SERVER;
     case k_INPUT_ENV: return m_ENV;
   }
   return empty_array();
 }
Example #14
0
Array HashCollection::toArray() {
  if (!m_size) {
    return empty_array();
  }
  auto ad = arrayData()->toPHPArray(true);
  if (UNLIKELY(ad->size() < m_size)) warnOnStrIntDup();
  assert(m_size);
  assert(ad->m_pos == 0);
  return Array::attach(ad);
}
Example #15
0
Array HHVM_FUNCTION(heapgraph_stats, const Resource& resource) {
  auto hgptr = get_valid_heapgraph_context_resource(resource, __FUNCTION__);
  if (!hgptr) return empty_array();
  auto result = make_map_array(
    s_nodes, Variant(hgptr->hg.nodes.size()),
    s_edges, Variant(hgptr->hg.ptrs.size()),
    s_roots, Variant(hgptr->hg.roots.size())
  );
  return result;
}
Example #16
0
void EventHook::DoMemoryThresholdCallback() {
  clearSurpriseFlag(MemThresholdFlag);
  if (!g_context->m_memThresholdCallback.isNull()) {
    VMRegAnchor _;
    try {
      vm_call_user_func(g_context->m_memThresholdCallback, empty_array());
    } catch (Object& ex) {
      raise_error("Uncaught exception escaping mem Threshold callback: %s",
                  ex.toString().data());
    }
  }
}
Example #17
0
Array HHVM_FUNCTION(libxml_get_errors) {
  xmlErrorVec* error_list = &tl_libxml_request_data->m_errors;
  const auto length = error_list->size();
  if (!length) {
    return empty_array();
  }
  PackedArrayInit ret(length);
  for (int64_t i = 0; i < length; i++) {
    ret.append(create_libxmlerror(error_list->at(i)));
  }
  return ret.toArray();
}
Example #18
0
Array c_WaitableWaitHandle::t_getparents() {
  // no parent data available if finished
  if (isFinished()) {
    return empty_array();
  }

  Array result = Array::Create();
  c_BlockableWaitHandle* curr = m_firstParent;

  while (curr) {
    result.append(curr);
    curr = curr->getNextParent();
  }

  return result;
}
Example #19
0
Array Variant::toArrayHelper() const {
  switch (m_type) {
  case KindOfUninit:
  case KindOfNull:    return empty_array();
  case KindOfInt64:   return Array::Create(m_data.num);
  case KindOfStaticString:
  case KindOfString:  return Array::Create(m_data.pstr);
  case KindOfArray:   return Array(m_data.parr);
  case KindOfObject:  return m_data.pobj->o_toArray();
  case KindOfResource: return m_data.pres->o_toArray();
  case KindOfRef: return m_data.pref->var()->toArray();
  default:
    break;
  }
  return Array::Create(*this);
}
Example #20
0
Variant ArrayUtil::Reverse(const Array& input, bool preserve_keys /* = false */) {
  if (input.empty()) {
    return empty_array();
  }

  auto ret = Array::Create();
  auto pos_limit = input->iter_end();
  for (ssize_t pos = input->iter_last(); pos != pos_limit;
       pos = input->iter_rewind(pos)) {
    auto const key = input->nvGetKey(pos);
    if (preserve_keys || isStringType(key.m_type)) {
      ret.setWithRef(key, input->atPos(pos), true);
    } else {
      ret.appendWithRef(input->atPos(pos));
    }
  }
  return ret;
}
Example #21
0
Variant HHVM_FUNCTION(preg_replace_callback_array,
                      const Variant& patterns_and_callbacks,
                      const Variant& subject,
                      int limit /* = -1 */,
                      VRefParam count /* = uninit_null() */) {
  if (!patterns_and_callbacks.isArray()) {
    raise_warning(
      "%s() expects parameter 1 to be an array, %s given",
      __FUNCTION__+2 /* +2 removes the "f_" prefix */,
      getDataTypeString(patterns_and_callbacks.getType()).c_str()
    );
    return init_null();
  }

  // Now see if we need to raise any warnings because of not having a
  // valid callback function
  for (ArrayIter iter(patterns_and_callbacks.toArray()); iter; ++iter) {
    if (!is_callable(iter.second())) {
      raise_warning("Not a valid callback function %s",
                    iter.second().toString().data());
      return subject.isString() ? empty_string_variant()
                                : Variant(empty_array());
    }
  }

  if (subject.isString()) {
    Array subject_arr = Array::Create();
    subject_arr.add(0, subject.toString());
    Variant ret = preg_replace_callback_array_impl(
      patterns_and_callbacks, subject_arr, limit, count
    );
    // ret[0] could be an empty string
    return ret.isArray() ? ret.toArray()[0] : init_null();
  } else if (subject.isArray()) {
    return preg_replace_callback_array_impl(
      patterns_and_callbacks, subject.toArray(), limit, count
    );
  } else {
    // No warning is given here, just return null
    return init_null();
  }
}
Example #22
0
Variant HHVM_METHOD(SQLite3, querysingle,
                    const String& sql,
                    bool entire_row /* = false */) {
  auto *data = Native::data<SQLite3>(this_);
  SYNC_VM_REGS_SCOPED();
  data->validate();
  if (!sql.empty()) {
    Variant stmt = HHVM_MN(SQLite3, prepare)(this_, sql);
    if (!same(stmt, false)) {
      Object obj_stmt = stmt.toObject();
      assert(obj_stmt.instanceof(SQLite3Stmt::getClass()));
      sqlite3_stmt *pstmt =
        Native::data<SQLite3Stmt>(obj_stmt)->m_raw_stmt;
      switch (sqlite3_step(pstmt)) {
      case SQLITE_ROW: /* Valid Row */
        if (entire_row) {
          Array ret = Array::Create();
          for (int i = 0; i < sqlite3_data_count(pstmt); i++) {
            ret.set(String((char*)sqlite3_column_name(pstmt, i), CopyString),
                    get_column_value(pstmt, i));
          }
          return ret;
        }
        return get_column_value(pstmt, 0);
      case SQLITE_DONE: /* Valid but no results */
        if (entire_row) {
          return empty_array();
        } else {
          return init_null();
        }
      default:
        raise_warning("Unable to execute statement: %s",
                      sqlite3_errmsg(data->m_raw_db));
      }
    }
  }
  return false;
}
Example #23
0
Variant HHVM_FUNCTION(getaddrinfo,
                      const String& host,
                      const String& port,
                      int family /* = 0 */,
                      int socktype /* = 0 */,
                      int protocol /* = 0 */,
                      int flags /* = 0 */) {
  const char *hptr = NULL, *pptr = NULL;
  if (!host.empty()) {
    hptr = host.c_str();
  }
  if (!port.empty()) {
    pptr = port.c_str();
  }

  struct addrinfo hints, *res;
  struct addrinfo *res0 = NULL;
  int error;

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = family;
  hints.ai_socktype = socktype;
  hints.ai_protocol = protocol;
  hints.ai_flags = flags;
  error = getaddrinfo(hptr, pptr, &hints, &res0);

  if (error) {
    raise_warning("%s", gai_strerror(error));

    if (res0) {
      freeaddrinfo(res0);
    }
    return false;
  }

  Array ret = Array::Create();

  for (res = res0; res; res = res->ai_next) {
    Array data = make_map_array(
      s_family, res->ai_family,
      s_socktype, res->ai_socktype,
      s_protocol, res->ai_protocol
    );

    switch (res->ai_addr->sa_family) {
      case AF_INET:
      {
        struct sockaddr_in *a;
        String buffer = ipaddr_convert(res->ai_addr, sizeof(*a));
        if (!buffer.empty()) {
          a = (struct sockaddr_in *)res->ai_addr;
          data.set(
            s_sockaddr,
            make_map_array(
              s_address, buffer,
              s_port, ntohs(a->sin_port)
            )
          );
        }
        break;
      }
      case AF_INET6:
      {
        struct sockaddr_in6 *a;
        String buffer = ipaddr_convert(res->ai_addr, sizeof(*a));
        if (!buffer.empty()) {
          a = (struct sockaddr_in6 *)res->ai_addr;
          data.set(
            s_sockaddr,
            make_map_array(
              s_address, buffer,
              s_port, ntohs(a->sin6_port),
              s_flow_info, (int32_t)a->sin6_flowinfo,
              s_scope_id, (int32_t)a->sin6_scope_id
            )
          );
        }
        break;
      }
      default:
        data.set(s_sockaddr, empty_array());
        break;
    }

    ret.append(data);
  }

  if (res0) {
    freeaddrinfo(res0);
  }

  return ret;
}
Example #24
0
void ResourceData::serializeImpl(VariableSerializer *serializer) const {
  serializer->pushResourceInfo(o_getResourceName(), o_id);
  empty_array().serialize(serializer);
  serializer->popResourceInfo();
}
Example #25
0
Array HHVM_FUNCTION(heapgraph_node, const Resource& resource, int64_t index) {
  auto hgptr = get_valid_heapgraph_context_resource(resource, __FUNCTION__);
  if (!hgptr) return empty_array();
  if (index < 0 || index >= (hgptr->hg.nodes.size())) return empty_array();
  return createPhpNode(hgptr, index);
}
Example #26
0
size_t check_request_surprise() {
  auto& info = TI();
  auto& p = info.m_reqInjectionData;

  auto const flags = fetchAndClearSurpriseFlags();
  auto const do_timedout = (flags & TimedOutFlag) && !p.getDebuggerAttached();
  auto const do_memExceeded = flags & MemExceededFlag;
  auto const do_memThreshold = flags & MemThresholdFlag;
  auto const do_signaled = flags & SignaledFlag;
  auto const do_cpuTimedOut =
    (flags & CPUTimedOutFlag) && !p.getDebuggerAttached();
  auto const do_GC = flags & PendingGCFlag;

  // Start with any pending exception that might be on the thread.
  auto pendingException = info.m_pendingException;
  info.m_pendingException = nullptr;

  if (do_timedout) {
    p.setCPUTimeout(0);  // Stop CPU timer so we won't time out twice.
    if (pendingException) {
      setSurpriseFlag(TimedOutFlag);
    } else {
      pendingException = generate_request_timeout_exception();
    }
  }
  // Don't bother with the CPU timeout if we're already handling a wall timeout.
  if (do_cpuTimedOut && !do_timedout) {
    p.setTimeout(0);  // Stop wall timer so we won't time out twice.
    if (pendingException) {
      setSurpriseFlag(CPUTimedOutFlag);
    } else {
      pendingException = generate_request_cpu_timeout_exception();
    }
  }
  if (do_memExceeded) {
    if (pendingException) {
      setSurpriseFlag(MemExceededFlag);
    } else {
      pendingException = generate_memory_exceeded_exception();
    }
  }
  if (do_memThreshold) {
    clearSurpriseFlag(MemThresholdFlag);
    if (!g_context->m_memThresholdCallback.isNull()) {
      VMRegAnchor _;
      try {
        vm_call_user_func(g_context->m_memThresholdCallback, empty_array());
      } catch (Object& ex) {
        raise_error("Uncaught exception escaping mem Threshold callback: %s",
                    ex.toString().data());
      }
    }
  }
  if (do_GC) {
    VMRegAnchor _;
    if (RuntimeOption::EvalEnableGC) {
      MM().collect("surprise");
    } else {
      MM().checkHeap("surprise");
    }
  }
  if (do_signaled) {
    HHVM_FN(pcntl_signal_dispatch)();
  }

  if (pendingException) {
    pendingException->throwException();
  }
  return flags;
}
Example #27
0
// This function takes an array of arrays, each of which is of the
// form array($dbh, ...).  The only thing that matters in the inner
// arrays is the first element being a MySQL instance.  It then
// procedes to block for up to 'timeout' seconds, waiting for the
// first actionable descriptor(s), which it then returns in the form
// of the original arrays passed in.  The intention is the caller
// would include other information they care about in the tail of the
// array so they can decide how to act on the
// potentially-now-queryable descriptors.
//
// This function is a poor shadow of how the async library can be
// used; for more complex cases, we'd use libevent and share our event
// loop with other IO operations such as memcache ops, thrift calls,
// etc.  That said, this function is reasonably efficient for most use
// cases.
static Variant HHVM_FUNCTION(mysql_async_wait_actionable, const Array& items,
                                                   double timeout) {
  size_t count = items.size();
  if (count == 0 || timeout < 0) {
    return empty_array();
  }

  struct pollfd* fds = (struct pollfd*)calloc(count, sizeof(struct pollfd));
  SCOPE_EXIT { free(fds); };

  // Walk our input, determine what kind of poll() operation is
  // necessary for the descriptor in question, and put an entry into
  // fds.
  int nfds = 0;
  for (ArrayIter iter(items); iter; ++iter) {
    Array entry = iter.second().toArray();
    if (entry.size() < 1) {
      raise_warning("element %d did not have at least one entry",
                   nfds);
      return empty_array();
    }

    auto conn = cast<MySQLResource>(entry.rvalAt(0))->mysql()->get();

    if (conn->async_op_status == ASYNC_OP_UNSET) {
      raise_warning("runtime/ext_mysql: no pending async operation in "
                    "progress");
      return empty_array();
    }

    pollfd* fd = &fds[nfds++];
    fd->fd = mysql_get_file_descriptor(conn);
    if (conn->net.async_blocking_state == NET_NONBLOCKING_READ) {
      fd->events = POLLIN;
    } else {
      fd->events = POLLOUT;
    }
    fd->revents = 0;
  }

  // The poll itself; either the timeout is hit or one or more of the
  // input fd's is ready.
  int timeout_millis = static_cast<long>(timeout * 1000);
  int res = poll(fds, nfds, timeout_millis);
  if (res == -1) {
    raise_warning("unable to poll [%d]: %s", errno,
                  folly::errnoStr(errno).c_str());
    return empty_array();
  }

  // Now just find the ones that are ready, and copy the corresponding
  // arrays from our input array into our return value.
  Array ret = Array::Create();
  nfds = 0;
  for (ArrayIter iter(items); iter; ++iter) {
    Array entry = iter.second().toArray();
    if (entry.size() < 1) {
      raise_warning("element %d did not have at least one entry",
                   nfds);
      return empty_array();
    }

    auto conn = cast<MySQLResource>(entry.rvalAt(0))->mysql()->get();

    pollfd* fd = &fds[nfds++];
    if (fd->fd != mysql_get_file_descriptor(conn)) {
      raise_warning("poll returned events out of order wtf");
      continue;
    }
    if (fd->revents != 0) {
      ret.append(iter.second());
    }
  }

  return ret;
}
Example #28
0
void trie_tree_free(trie_tree* tree)
{
  assert(tree);
  empty_array(&tree->node_array);
  free(tree);
}
Example #29
0
Array createBacktrace(const BacktraceArgs& btArgs) {
  auto bt = Array::Create();

  // If there is a parser frame, put it at the beginning of the backtrace.
  if (btArgs.m_parserFrame) {
    bt.append(
      make_map_array(
        s_file, btArgs.m_parserFrame->filename,
        s_line, btArgs.m_parserFrame->lineNumber
      )
    );
  }

  VMRegAnchor _;
  // If there are no VM frames, we're done.
  if (!rds::header() || !vmfp()) return bt;

  int depth = 0;
  ActRec* fp = nullptr;
  Offset pc = 0;

  // Get the fp and pc of the top frame (possibly skipping one frame).

  if (btArgs.m_skipTop) {
    fp = getPrevActRec(vmfp(), &pc);
    // We skipped over the only VM frame, we're done.
    if (!fp) return bt;
  } else {
    fp = vmfp();
    auto const unit = fp->func()->unit();
    assert(unit);
    pc = unit->offsetOf(vmpc());
  }

  // Handle the top frame.
  if (btArgs.m_withSelf) {
    // Builtins don't have a file and line number.
    if (!fp->func()->isBuiltin()) {
      auto const unit = fp->func()->unit();
      assert(unit);
      auto const filename = fp->func()->filename();

      ArrayInit frame(btArgs.m_parserFrame ? 4 : 2, ArrayInit::Map{});
      frame.set(s_file, Variant{const_cast<StringData*>(filename)});
      frame.set(s_line, unit->getLineNumber(pc));
      if (btArgs.m_parserFrame) {
        frame.set(s_function, s_include);
        frame.set(s_args, Array::Create(btArgs.m_parserFrame->filename));
      }
      bt.append(frame.toVariant());
      depth++;
    }
  }

  // Handle the subsequent VM frames.
  Offset prevPc = 0;
  for (auto prevFp = getPrevActRec(fp, &prevPc);
       fp != nullptr && (btArgs.m_limit == 0 || depth < btArgs.m_limit);
       fp = prevFp, pc = prevPc,
         prevFp = getPrevActRec(fp, &prevPc)) {
    // Do not capture frame for HPHP only functions.
    if (fp->func()->isNoInjection()) continue;

    ArrayInit frame(7, ArrayInit::Map{});

    auto const curUnit = fp->func()->unit();
    auto const curOp = *reinterpret_cast<const Op*>(curUnit->at(pc));
    auto const isReturning =
      curOp == Op::RetC || curOp == Op::RetV ||
      curOp == Op::CreateCont || curOp == Op::Await ||
      fp->localsDecRefd();

    // Builtins and generators don't have a file and line number
    if (prevFp && !prevFp->func()->isBuiltin()) {
      auto const prevUnit = prevFp->func()->unit();
      auto prevFile = prevUnit->filepath();
      if (prevFp->func()->originalFilename()) {
        prevFile = prevFp->func()->originalFilename();
      }
      assert(prevFile);
      frame.set(s_file, Variant{const_cast<StringData*>(prevFile)});

      // In the normal method case, the "saved pc" for line number printing is
      // pointing at the cell conversion (Unbox/Pop) instruction, not the call
      // itself. For multi-line calls, this instruction is associated with the
      // subsequent line which results in an off-by-n. We're subtracting one
      // in order to look up the line associated with the FCall/FCallArray
      // instruction. Exception handling and the other opcodes (ex. BoxR)
      // already do the right thing. The emitter associates object access with
      // the subsequent expression and this would be difficult to modify.
      auto const opAtPrevPc =
        *reinterpret_cast<const Op*>(prevUnit->at(prevPc));
      Offset pcAdjust = 0;
      if (opAtPrevPc == Op::PopR ||
          opAtPrevPc == Op::UnboxR ||
          opAtPrevPc == Op::UnboxRNop) {
        pcAdjust = 1;
      }
      frame.set(s_line,
                prevFp->func()->unit()->getLineNumber(prevPc - pcAdjust));
    }

    // Check for include.
    String funcname{const_cast<StringData*>(fp->func()->name())};
    if (fp->func()->isClosureBody()) {
      // Strip the file hash from the closure name.
      String fullName{const_cast<StringData*>(fp->func()->baseCls()->name())};
      funcname = fullName.substr(0, fullName.find(';'));
    }

    // Check for pseudomain.
    if (funcname.empty()) {
      if (!prevFp && !btArgs.m_withPseudoMain) continue;
      else if (!prevFp) funcname = s_main;
      else funcname = s_include;
    }

    frame.set(s_function, funcname);

    if (!funcname.same(s_include)) {
      // Closures have an m_this but they aren't in object context.
      auto ctx = arGetContextClass(fp);
      if (ctx != nullptr && !fp->func()->isClosureBody()) {
        frame.set(s_class, Variant{const_cast<StringData*>(ctx->name())});
        if (fp->hasThis() && !isReturning) {
          if (btArgs.m_withThis) {
            frame.set(s_object, Object(fp->getThis()));
          }
          frame.set(s_type, s_arrow);
        } else {
          frame.set(s_type, s_double_colon);
        }
      }
    }

    bool const mayUseVV = fp->func()->attrs() & AttrMayUseVV;

    auto const withNames = btArgs.m_withArgNames;
    auto const withValues = btArgs.m_withArgValues;
    if (!btArgs.m_withArgNames && !btArgs.m_withArgValues) {
      // do nothing
    } else if (funcname.same(s_include)) {
      if (depth != 0) {
        auto filepath = const_cast<StringData*>(curUnit->filepath());
        frame.set(s_args, make_packed_array(filepath));
      }
    } else if (!RuntimeOption::EnableArgsInBacktraces || isReturning) {
      // Provide an empty 'args' array to be consistent with hphpc.
      frame.set(s_args, empty_array());
    } else {
      auto args = Array::Create();
      auto const nparams = fp->func()->numNonVariadicParams();
      auto const nargs = fp->numArgs();
      auto const nformals = std::min<int>(nparams, nargs);

      if (UNLIKELY(mayUseVV) &&
          UNLIKELY(fp->hasVarEnv() && fp->getVarEnv()->getFP() != fp)) {
        // VarEnv is attached to eval or debugger frame, other than the current
        // frame. Access locals thru VarEnv.
        auto varEnv = fp->getVarEnv();
        auto func = fp->func();
        for (int i = 0; i < nformals; i++) {
          auto const argname = func->localVarName(i);
          auto const tv = varEnv->lookup(argname);

          Variant val;
          if (tv != nullptr) { // the variable hasn't been unset
            val = withValues ? tvAsVariant(tv) : "";
          }

          if (withNames) {
            args.set(String(const_cast<StringData*>(argname)), val);
          } else {
            args.append(val);
          }
        }
      } else {
        for (int i = 0; i < nformals; i++) {
          Variant val = withValues ? tvAsVariant(frame_local(fp, i)) : "";

          if (withNames) {
            auto const argname = fp->func()->localVarName(i);
            args.set(String(const_cast<StringData*>(argname)), val);
          } else {
            args.append(val);
          }
        }
      }

      // Builtin extra args are not stored in varenv.
      if (UNLIKELY(mayUseVV) && nargs > nparams && fp->hasExtraArgs()) {
        for (int i = nparams; i < nargs; i++) {
          auto arg = fp->getExtraArg(i - nparams);
          args.append(tvAsVariant(arg));
        }
      }
      frame.set(s_args, args);
    }

    if (btArgs.m_withMetadata && !isReturning) {
      if (UNLIKELY(mayUseVV) && UNLIKELY(fp->hasVarEnv())) {
        auto tv = fp->getVarEnv()->lookup(s_86metadata.get());
        if (tv != nullptr && tv->m_type != KindOfUninit) {
          frame.set(s_metadata, tvAsVariant(tv));
        }
      } else {
        auto local = fp->func()->lookupVarId(s_86metadata.get());
        if (local != kInvalidId) {
          auto tv = frame_local(fp, local);
          if (tv->m_type != KindOfUninit) {
            frame.set(s_metadata, tvAsVariant(tv));
          }
        }
      }
    }

    bt.append(frame.toVariant());
    depth++;
  }

  return bt;
}
Example #30
0
Variant HHVM_FUNCTION(socket_select,
                      VRefParam read,
                      VRefParam write,
                      VRefParam except,
                      const Variant& vtv_sec,
                      int tv_usec /* = 0 */) {
  int count = 0;
  if (!read.isNull()) {
    count += read.toArray().size();
  }
  if (!write.isNull()) {
    count += write.toArray().size();
  }
  if (!except.isNull()) {
    count += except.toArray().size();
  }
  if (!count) {
    return false;
  }

  struct pollfd *fds = (struct pollfd *)calloc(count, sizeof(struct pollfd));
  count = 0;
  if (!read.isNull()) {
    sock_array_to_fd_set(read.toArray(), fds, count, POLLIN);
  }
  if (!write.isNull()) {
    sock_array_to_fd_set(write.toArray(), fds, count, POLLOUT);
  }
  if (!except.isNull()) {
    sock_array_to_fd_set(except.toArray(), fds, count, POLLPRI);
  }
  if (!count) {
    raise_warning("no resource arrays were passed to select");
    free(fds);
    return false;
  }

  IOStatusHelper io("socket_select");
  int timeout_ms = -1;
  if (!vtv_sec.isNull()) {
    timeout_ms = vtv_sec.toInt32() * 1000 + tv_usec / 1000;
  }

  /* slight hack to support buffered data; if there is data sitting in the
   * read buffer of any of the streams in the read array, let's pretend
   * that we selected, but return only the readable sockets */
  if (!read.isNull()) {
    auto hasData = Array::Create();
    for (ArrayIter iter(read.toArray()); iter; ++iter) {
      auto file = cast<File>(iter.second());
      if (file->bufferedLen() > 0) {
        hasData.append(iter.second());
      }
    }
    if (hasData.size() > 0) {
      if (!write.isNull()) {
        write = empty_array();
      }
      if (!except.isNull()) {
        except = empty_array();
      }
      read = hasData;
      free(fds);
      return hasData.size();
    }
  }

  int retval = poll(fds, count, timeout_ms);
  if (retval == -1) {
    raise_warning("unable to select [%d]: %s", errno,
                  folly::errnoStr(errno).c_str());
    free(fds);
    return false;
  }

  count = 0;
  int nfds = 0;
  if (!read.isNull()) {
    sock_array_from_fd_set(read, fds, nfds, count, POLLIN|POLLERR|POLLHUP);
  }
  if (!write.isNull()) {
    sock_array_from_fd_set(write, fds, nfds, count, POLLOUT|POLLERR);
  }
  if (!except.isNull()) {
    sock_array_from_fd_set(except, fds, nfds, count, POLLPRI|POLLERR);
  }

  free(fds);
  return count;
}