Exemplo n.º 1
0
TypedValue HHVM_FUNCTION(preg_match,
                         StringArg pattern, StringArg subject,
                         OutputArg matches /* = null */,
                         int flags /* = 0 */, int offset /* = 0 */) {
  return tvReturn(preg_match(StrNR(pattern.get()), StrNR(subject.get()),
                             matches.get() ? matches->var() : nullptr,
                             flags, offset));
}
Exemplo n.º 2
0
CachedUnit createUnitFromUrl(const StringData* const requestedPath) {
  auto const w = Stream::getWrapperFromURI(StrNR(requestedPath));
  if (!w) return CachedUnit{};
  auto const f = w->open(StrNR(requestedPath), "r", 0, null_variant);
  if (!f) return CachedUnit{};
  StringBuffer sb;
  sb.read(f);
  return createUnitFromString(requestedPath->data(), sb.detach());
}
Exemplo n.º 3
0
// When running via the CLI server special access checks may need to be
// performed, and in the event that the server is unable to load the file an
// alternative per client cache may be used.
NonRepoUnitCache& getNonRepoCache(const StringData* rpath,
                                  Stream::Wrapper*& w) {
  if (auto uc = get_cli_ucred()) {
    if (!(w = Stream::getWrapperFromURI(StrNR(rpath)))) {
      return s_nonRepoUnitCache;
    }

    auto unit_check_quarantine = [&] () -> NonRepoUnitCache& {
      if (!RuntimeOption::EvalUnixServerQuarantineUnits) {
        return s_nonRepoUnitCache;
      }
      auto iter = s_perUserUnitCaches.find(uc->uid);
      if (iter != s_perUserUnitCaches.end()) return *iter->second;
      auto cache = new NonRepoUnitCache;
      auto res = s_perUserUnitCaches.insert(uc->uid, cache);
      if (!res.second) delete cache;
      return *res.first->second;
    };

    // If the server cannot access rpath attempt to open the unit on the
    // client. When UnixServerQuarantineUnits is set store units opened by
    // clients in per UID caches which are never accessible by server web
    // requests.
    if (access(rpath->data(), R_OK) == -1) {
      return unit_check_quarantine();
    }

    // When UnixServerVerifyExeAccess is set clients may not execute units if
    // they cannot read them, even when the server has access. To verify that
    // clients have access they are asked to open the file for read access,
    // and using fstat the server verifies that the file it sees is identical
    // to the unit opened by the client.
    if (RuntimeOption::EvalUnixServerVerifyExeAccess) {
      // Stream wrappers can reenter PHP via user defined callbacks. Roll this
      // operation into a single event
      rqtrace::EventGuard trace{"STREAM_WRAPPER_OPEN"};
      rqtrace::DisableTracing disable;

      struct stat local, remote;
      auto remoteFile = w->open(StrNR(rpath), "r", 0, nullptr);
      if (!remoteFile ||
          fcntl(remoteFile->fd(), F_GETFL) != O_RDONLY ||
          fstat(remoteFile->fd(), &remote) != 0 ||
          stat(rpath->data(), &local) != 0 ||
          remote.st_dev != local.st_dev ||
          remote.st_ino != local.st_ino) {
        return unit_check_quarantine();
      }
    }

    // When the server is able to read the file prefer to access it that way,
    // in all modes units loaded by the server are cached for all clients.
    w = nullptr;
  }
  return s_nonRepoUnitCache;
}
Exemplo n.º 4
0
NamedEntity* NamedEntity::get(const StringData* str,
                              bool allowCreate /* = true */,
                              String* normalizedStr /* = nullptr */) {
  if (UNLIKELY(!s_namedDataMap)) {
    initializeNamedDataMap();
  }

  auto it = s_namedDataMap->find(str);
  if (LIKELY(it != s_namedDataMap->end())) {
    return &it->second;
  }

  if (needsNSNormalization(str)) {
    auto normStr = normalizeNS(StrNR(str).asString());
    if (normalizedStr) {
      *normalizedStr = normStr;
    }
    return get(normStr.get(), allowCreate, normalizedStr);
  }

  if (LIKELY(allowCreate)) {
    return insertNamedEntity(str);
  }
  return nullptr;
}
Exemplo n.º 5
0
Variant HHVM_FUNCTION(class_uses, const Variant& obj,
                                  bool autoload /* = true */) {
  Class* cls;
  if (obj.isString()) {
    cls = Unit::getClass(obj.getStringData(), autoload);
    if (!cls) {
      String err = "class_uses(): Class %s does not exist";
      if (autoload) {
        err += " and could not be loaded";
      }
      raise_warning(err.c_str(), obj.toString().c_str());
      return false;
    }
  } else if (obj.isObject()) {
    cls = obj.getObjectData()->getVMClass();
  } else {
    raise_warning("class_uses(): object or string expected");
    return false;
  }
  auto &usedTraits = cls->preClass()->usedTraits();
  ArrayInit ret(usedTraits.size(), ArrayInit::Map{});
  for (auto const& traitName : usedTraits) {
    ret.set(StrNR(traitName), VarNR(traitName).tv());
  }
  return ret.toArray();
}
Exemplo n.º 6
0
CVarRef GlobalArrayWrapper::get(const StringData* k,
                                bool error /* = false */) const {
  if (exists(k)) {
    return m_globals->get(StrNR(k));
  }
  return null_variant;
}
Exemplo n.º 7
0
bool findFile(const StringData* path, struct stat* s, bool allow_dir,
              Stream::Wrapper* w, const Native::FuncTable& nativeFuncs) {
  // We rely on this side-effect in RepoAuthoritative mode right now, since the
  // stat information is an output-param of resolveVmInclude, but we aren't
  // really going to call stat.
  s->st_mode = 0;

  if (RuntimeOption::RepoAuthoritative) {
    return lookupUnitRepoAuth(path, nativeFuncs).unit != nullptr;
  }

  if (StatCache::stat(path->data(), s) == 0) {
    // The call explicitly populates the struct for dirs, but returns false for
    // them because it is geared toward file includes.
    return allow_dir || !S_ISDIR(s->st_mode);
  }

  if (w) {
    // Stream wrappers can reenter PHP via user defined callbacks. Roll this
    // operation into a single event
    rqtrace::EventGuard trace{"STREAM_WRAPPER_STAT"};
    rqtrace::DisableTracing disable;

    if (w->stat(StrNR(path), s) == 0) {
      return allow_dir || !S_ISDIR(s->st_mode);
    }
  }
  return false;
}
Exemplo n.º 8
0
const EnumValues* EnumCache::loadEnumValues(const Class* klass,
                                            bool recurse) {
  auto const numConstants = klass->numConstants();
  auto values = Array::CreateDArray();
  auto names = Array::CreateDArray();
  auto const consts = klass->constants();
  bool persist = true;
  for (size_t i = 0; i < numConstants; i++) {
    if (consts[i].isAbstract() || consts[i].isType()) {
      continue;
    }
    if (consts[i].cls != klass && !recurse) {
      continue;
    }
    Cell value = consts[i].val;
    // Handle dynamically set constants
    if (value.m_type == KindOfUninit) {
      persist = false;
      value = klass->clsCnsGet(consts[i].name);
    }
    assertx(value.m_type != KindOfUninit);
    if (UNLIKELY(!(isIntType(value.m_type) || tvIsString(&value)))) {
      // only int and string values allowed for enums.
      std::string msg;
      msg += klass->name()->data();
      msg += " enum can only contain string and int values";
      EnumCache::failLookup(msg);
    }
    values.set(StrNR(consts[i].name), cellAsCVarRef(value));

    // Manually perform int-like key coercion even if names is a dict for
    // backwards compatibility.
    int64_t n;
    if (tvIsString(&value) && value.m_data.pstr->isStrictlyInteger(n)) {
      names.set(n, make_tv<KindOfPersistentString>(consts[i].name));
    } else {
      names.set(value, make_tv<KindOfPersistentString>(consts[i].name), true);
    }
  }

  assertx(names.isDictOrDArray());
  assertx(values.isDictOrDArray());

  // If we saw dynamic constants we cannot cache the enum values across requests
  // as they may not be the same in every request.
  return persist
    ? cachePersistentEnumValues(
      klass,
      recurse,
      std::move(names),
      std::move(values))
    : cacheRequestEnumValues(
      klass,
      recurse,
      std::move(names),
      std::move(values));
}
Exemplo n.º 9
0
ArrayData *VectorArray::addLval(CVarRef k, Variant *&ret, bool copy) {
  ASSERT(!exists(k));
  Variant::TypedValueAccessor tva = k.getTypedAccessor();
  if (isIntKey(tva)) return VectorArray::addLval(getIntKey(tva), ret, copy);
  ASSERT(k.isString());
  ZendArray *a = escalateToZendArray();
  a->addLval(StrNR(getStringKey(tva)), ret, false);
  return a;
}
Exemplo n.º 10
0
CachedUnit lookupUnitNonRepoAuth(StringData* requestedPath,
                                 const struct stat& statInfo) {
  if (strstr(requestedPath->data(), "://") != nullptr) {
    // URL-based units are not currently cached in memory, but the Repo still
    // caches them on disk.
    return createUnitFromUrl(requestedPath);
  }

  // The string we're using as a key must be static, because we're using it as
  // a key in the cache (across requests).
  auto const path =
    makeStaticString(
      // XXX: it seems weird we have to do this even though we already ran
      // resolveVmInclude.
      (requestedPath->data()[0] == '/'
        ? requestedPath
        : String(SourceRootInfo::GetCurrentSourceRoot()) + StrNR(requestedPath)
      ).get()
    );

  NonRepoUnitCache::accessor acc;
  if (!s_nonRepoUnitCache.insert(acc, path)) {
    if (!isChanged(acc->second, statInfo)) {
      return acc->second.cachedUnit;
    }
  }

  /*
   * NB: the new-unit creation path is here, and is done while holding the tbb
   * lock on s_nonRepoUnitCache.  This was originally done deliberately to
   * avoid wasting time in the compiler (during server startup, many requests
   * hit the same code initial paths that are shared, and would all be
   * compiling the same files).  It's not 100% clear if this is the best way to
   * handle that idea, though (tbb locks spin aggressively and are expected to
   * be low contention).
   */

  /*
   * Don't cache if createNewUnit returns an empty CachedUnit---we'll need to
   * try again anyway if someone tries to load this path, since it might exist
   * later.
   *
   * If there was a unit for this path already, we need to put it on the
   * Treadmill for eventual reclaimation.  We can't delete it immediately
   * because other requests may still be using it.
   */
  auto const cu = createUnitFromFile(path);
  if (auto const oldUnit = acc->second.cachedUnit.unit) {
    Treadmill::enqueue([oldUnit] { reclaimUnit(oldUnit); });
  }
  acc->second.cachedUnit = cu;
  acc->second.mtime      = statInfo.st_mtim;
  acc->second.ino        = statInfo.st_ino;
  acc->second.devId      = statInfo.st_dev;
  return cu;
}
Exemplo n.º 11
0
CachedUnit createUnitFromUrl(const StringData* const requestedPath,
                             const Native::FuncTable& nativeFuncs,
                             FileLoadFlags& flags) {
  auto const w = Stream::getWrapperFromURI(StrNR(requestedPath));
  StringBuffer sb;
  {
    // Stream wrappers can reenter PHP via user defined callbacks. Roll this
    // operation into a single event
    rqtrace::EventGuard trace{"STREAM_WRAPPER_OPEN"};
    rqtrace::DisableTracing disable;

    if (!w) return CachedUnit{};
    auto const f = w->open(StrNR(requestedPath), "r", 0, nullptr);
    if (!f) return CachedUnit{};
    sb.read(f.get());
  }
  OptLog ent;
  return createUnitFromString(requestedPath->data(), sb.detach(), nullptr, ent,
                              nativeFuncs, RepoOptions::defaults(), flags);
}
Exemplo n.º 12
0
HOT_FUNC_HPHP
ArrayData *VectorArray::set(CVarRef k, CVarRef v, bool copy) {
  Variant::TypedValueAccessor tva = k.getTypedAccessor();
  if (isIntKey(tva)) {
    return VectorArray::set(getIntKey(tva), v, copy);
  }
  ASSERT(k.isString());
  ZendArray *a = escalateToZendArray();
  a->add(StrNR(getStringKey(tva)), v, false);
  return a;
}
Exemplo n.º 13
0
Class* lookupKnownClass(Class** cache, const StringData* clsName) {
  Class* cls = *cache;
  assert(!cls); // the caller should already have checked
  assert(clsName->data()[0] != '\\'); // namespace names should be done earlier

  AutoloadHandler::s_instance->invokeHandler(
    StrNR(const_cast<StringData*>(clsName)));
  cls = *cache;

  if (UNLIKELY(!cls)) raise_error(Strings::UNKNOWN_CLASS, clsName->data());
  return cls;
}
Exemplo n.º 14
0
const EnumCache::EnumValues* EnumCache::loadEnumValues(const Class* klass,
                                                       bool recurse) {
  auto const numConstants = klass->numConstants();
  size_t foundOnClass = 0;
  Array values;
  Array names;
  auto const consts = klass->constants();
  for (size_t i = 0; i < numConstants; i++) {
    if (consts[i].isAbstract() || consts[i].isType()) {
      continue;
    }
    if (consts[i].m_class == klass) foundOnClass++;
    else if (!recurse) continue;
    Cell value = consts[i].m_val;
    // Handle dynamically set constants
    if (value.m_type == KindOfUninit) {
      value = klass->clsCnsGet(consts[i].m_name);
    }
    assert(value.m_type != KindOfUninit);
    if (UNLIKELY(!(isIntType(value.m_type) ||
        (tvIsString(&value) && value.m_data.pstr->isStatic())))) {
      // only int and string values allowed for enums. Moreover the strings
      // must be static
      std::string msg;
      msg += klass->name()->data();
      msg += " enum can only contain static string and int values";
      EnumCache::failLookup(msg);
    }
    values.set(StrNR(consts[i].m_name), cellAsCVarRef(value));
    names.set(cellAsCVarRef(value), VarNR(consts[i].m_name));
  }
  if (UNLIKELY(foundOnClass == 0)) {
    std::string msg;
    msg += klass->name()->data();
    msg += " enum must contain values";
    EnumCache::failLookup(msg);
  }

  {
    std::unique_ptr<EnumCache::EnumValues> enums(new EnumCache::EnumValues());
    enums->values = ArrayData::GetScalarArray(values.get());
    enums->names = ArrayData::GetScalarArray(names.get());

    intptr_t key = getKey(klass, recurse);
    EnumValuesMap::accessor acc;
    if (!m_enumValuesMap.insert(acc, key)) {
      return acc->second;
    }
    // add to the map the newly created values
    acc->second = enums.release();
    return acc->second;
  }
}
Exemplo n.º 15
0
static Array HHVM_METHOD(Closure, __debugInfo) {
  auto closure = c_Closure::fromObject(this_);

  Array ret = Array::Create();

  // Serialize 'use' parameters.
  if (auto useVars = closure->getUseVars()) {
    Array use;

    auto cls = this_->getVMClass();
    auto propsInfo = cls->declProperties();
    auto nProps = cls->numDeclProperties();
    for (size_t i = 0; i < nProps; ++i) {
      auto value = &useVars[i];
      use.setWithRef(Variant(StrNR(propsInfo[i].name)), tvAsCVarRef(value));
    }

    if (!use.empty()) {
      ret.set(s_static, use);
    }
  }

  auto const func = closure->getInvokeFunc();

  // Serialize function parameters.
  if (auto nParams = func->numParams()) {
   Array params;

   auto lNames = func->localNames();
   for (int i = 0; i < nParams; ++i) {
      auto str = String::attach(
        StringData::Make(s_varprefix.get(), lNames[i])
      );

      bool optional = func->params()[i].phpCode;
      if (auto mi = func->methInfo()) {
        optional = optional || mi->parameters[i]->valueText;
      }

      params.set(str, optional ? s_optional : s_required);
    }

    ret.set(s_parameter, params);
  }

  // Serialize 'this' object.
  if (closure->hasThis()) {
    ret.set(s_this, Object(closure->getThis()));
  }

  return ret;
}
Exemplo n.º 16
0
const EnumValues* EnumCache::loadEnumValues(const Class* klass,
                                            bool recurse) {
  auto const numConstants = klass->numConstants();
  auto values = Array::Create();
  auto names = Array::Create();
  auto const consts = klass->constants();
  bool persist = true;
  for (size_t i = 0; i < numConstants; i++) {
    if (consts[i].isAbstract() || consts[i].isType()) {
      continue;
    }
    if (consts[i].cls != klass && !recurse) {
      continue;
    }
    Cell value = consts[i].val;
    // Handle dynamically set constants
    if (value.m_type == KindOfUninit) {
      persist = false;
      value = klass->clsCnsGet(consts[i].name);
    }
    assert(value.m_type != KindOfUninit);
    if (UNLIKELY(!(isIntType(value.m_type) ||
        (tvIsString(&value) && value.m_data.pstr->isStatic())))) {
      // only int and string values allowed for enums. Moreover the strings
      // must be static
      std::string msg;
      msg += klass->name()->data();
      msg += " enum can only contain static string and int values";
      EnumCache::failLookup(msg);
    }
    values.set(StrNR(consts[i].name), cellAsCVarRef(value));
    names.set(value, make_tv<KindOfPersistentString>(consts[i].name));
  }

  // If we saw dynamic constants we cannot cache the enum values across requests
  // as they may not be the same in every request.
  return persist
    ? cachePersistentEnumValues(
      klass,
      recurse,
      std::move(names),
      std::move(values))
    : cacheRequestEnumValues(
      klass,
      recurse,
      std::move(names),
      std::move(values));
}
Exemplo n.º 17
0
bool register_intercept(const String& name, const Variant& callback,
                        const Variant& data) {
  StringIMap<Variant> &handlers = s_intercept_data->m_intercept_handlers;
  if (!callback.toBoolean()) {
    if (name.empty()) {
      s_intercept_data->m_global_handler.unset();
      StringIMap<Variant> empty;
      handlers.swap(empty);
    } else {
      auto tmp = handlers[name];
      auto it = handlers.find(name);
      if (it != handlers.end()) {
        auto tmp = it->second;
        handlers.erase(it);
      }
    }
    return true;
  }

  EventHook::EnableIntercept();

  Array handler = make_packed_array(callback, data);

  if (name.empty()) {
    s_intercept_data->m_global_handler = handler;
    StringIMap<Variant> empty;
    handlers.swap(empty);
  } else {
    handlers[name] = handler;
  }

  Lock lock(s_mutex);
  if (name.empty()) {
    for (auto& entry : s_registered_flags) {
      flag_maybe_intercepted(entry.second.second);
    }
  } else {
    StringData* sd = name.get();
    if (!sd->isStatic()) {
      sd = makeStaticString(sd);
    }
    auto &entry = s_registered_flags[StrNR(sd)];
    entry.first = true;
    flag_maybe_intercepted(entry.second);
  }

  return true;
}
Exemplo n.º 18
0
Array c_Closure::t___debuginfo() {
  Array ret = Array::Create();

  // Serialize 'use' parameters.
  if (auto propValues = propVec()) {
    Array use;

    auto propsInfo = getVMClass()->declProperties();
    for (size_t i = 0; i < getVMClass()->numDeclProperties(); ++i) {
      auto value = &propValues[i];
      use.setWithRef(Variant(StrNR(propsInfo[i].name)), tvAsCVarRef(value));
    }

    if (!use.empty()) {
      ret.set(s_static, use);
    }
  }

  auto const func = getInvokeFunc();

  // Serialize function parameters.
  if (func->numParams()) {
   Array params;

   for (int i = 0; i < func->numParams(); ++i) {
      auto str = String::attach(
        StringData::Make(s_varprefix.get(), func->localNames()[i])
      );

      bool optional = func->params()[i].phpCode;
      if (auto mi = func->methInfo()) {
        optional = optional || mi->parameters[i]->valueText;
      }

      params.set(str, optional ? s_optional : s_required);
    }

    ret.set(s_parameter, params);
  }

  // Serialize 'this' object.
  if (hasThis()) {
    ret.set(s_this, Object(getThis()));
  }

  return ret;
}
Exemplo n.º 19
0
Variant f_class_uses(const Variant& obj, bool autoload /* = true */) {
    Class* cls;
    if (obj.isString()) {
        cls = Unit::getClass(obj.getStringData(), autoload);
        if (!cls) {
            return false;
        }
    } else if (obj.isObject()) {
        cls = obj.getObjectData()->getVMClass();
    } else {
        return false;
    }
    Array ret(Array::Create());
    for (auto const& traitName : cls->preClass()->usedTraits()) {
        ret.set(StrNR(traitName), VarNR(traitName));
    }
    return ret;
}
Exemplo n.º 20
0
HOT_FUNC
bool f_array_key_exists(CVarRef key, CVarRef search) {
  const ArrayData *ad;

  auto const searchCell = search.asCell();
  if (LIKELY(searchCell->m_type == KindOfArray)) {
    ad = searchCell->m_data.parr;
  } else if (searchCell->m_type == KindOfObject) {
    ObjectData* obj = searchCell->m_data.pobj;
    if (obj->isCollection()) {
      return collectionOffsetContains(obj, key);
    }
    return f_array_key_exists(key, toArray(search));
  } else {
    throw_bad_type_exception("array_key_exists expects an array or an object; "
                             "false returned.");
    return false;
  }

  auto const cell = key.asCell();
  switch (cell->m_type) {
  case KindOfString:
  case KindOfStaticString: {
    int64_t n = 0;
    StringData *sd = cell->m_data.pstr;
    if (sd->isStrictlyInteger(n)) {
      return ad->exists(n);
    }
    return ad->exists(StrNR(sd));
  }
  case KindOfInt64:
    return ad->exists(cell->m_data.num);
  case KindOfUninit:
  case KindOfNull:
    return ad->exists(empty_string);
  default:
    break;
  }
  raise_warning("Array key should be either a string or an integer");
  return false;
}
Exemplo n.º 21
0
bool register_intercept(const String& name, CVarRef callback, CVarRef data) {
  StringIMap<Variant> &handlers = s_intercept_data->m_intercept_handlers;
  if (!callback.toBoolean()) {
    if (name.empty()) {
      s_intercept_data->m_global_handler.reset();
      handlers.clear();
    } else {
      handlers.erase(name);
    }
    return true;
  }

  EventHook::EnableIntercept();

  Array handler = make_packed_array(callback, data);

  if (name.empty()) {
    s_intercept_data->m_global_handler = handler;
    handlers.clear();
  } else {
    handlers[name] = handler;
  }

  Lock lock(s_mutex);
  if (name.empty()) {
    for (auto& entry : s_registered_flags) {
      flag_maybe_intercepted(entry.second.second);
    }
  } else {
    StringData* sd = name.get();
    if (!sd->isStatic()) {
      sd = makeStaticString(sd);
    }
    auto &entry = s_registered_flags[StrNR(sd)];
    entry.first = true;
    flag_maybe_intercepted(entry.second);
  }

  return true;
}
Exemplo n.º 22
0
Variant *get_intercept_handler(CStrRef name, char* flag) {
  TRACE(1, "get_intercept_handler %s flag is %d\n",
        name.get()->data(), (int)*flag);
  if (*flag == -1) {
    Lock lock(s_mutex);
    if (*flag == -1) {
      StringData *sd = name.get();
      if (!sd->isStatic()) {
        sd = StringData::GetStaticString(sd);
      }
      s_registered_flags[StrNR(sd)].push_back(flag);
      *flag = 0;
    }
  }

  Variant *handler = get_enabled_intercept_handler(name);
  if (handler == nullptr) {
    return nullptr;
  }
  *flag = 1;
  return handler;
}
Exemplo n.º 23
0
Variant *get_intercept_handler(const String& name, char* flag) {
  TRACE(1, "get_intercept_handler %s flag is %d\n",
        name.get()->data(), (int)*flag);
  if (*flag == -1) {
    Lock lock(s_mutex);
    if (*flag == -1) {
      StringData *sd = name.get();
      if (!sd->isStatic()) {
        sd = makeStaticString(sd);
      }
      auto &entry = s_registered_flags[StrNR(sd)];
      entry.second.push_back(flag);
      *flag = entry.first;
    }
    if (!*flag) return nullptr;
  }

  Variant *handler = get_enabled_intercept_handler(name);
  if (handler == nullptr) {
    return nullptr;
  }
  assert(*flag);
  return handler;
}
Exemplo n.º 24
0
Variant f_class_uses(const Variant& obj, bool autoload /* = true */) {
  Class* cls;
  if (obj.isString()) {
    cls = Unit::getClass(obj.getStringData(), autoload);
    if (!cls) {
      String err = "class_uses(): Class %s does not exist";
      if (autoload) {
        err += " and could not be loaded";
      }
      raise_warning(err.c_str(), obj.toString().c_str());
      return false;
    }
  } else if (obj.isObject()) {
    cls = obj.getObjectData()->getVMClass();
  } else {
    raise_warning("class_uses(): object or string expected");
    return false;
  }
  Array ret(Array::Create());
  for (auto const& traitName : cls->preClass()->usedTraits()) {
    ret.set(StrNR(traitName), VarNR(traitName));
  }
  return ret;
}
Exemplo n.º 25
0
HOT_FUNC
bool f_array_key_exists(CVarRef key, CVarRef search) {
  const ArrayData *ad;
  Variant::TypedValueAccessor sacc = search.getTypedAccessor();
  DataType saccType = Variant::GetAccessorType(sacc);
  if (LIKELY(saccType == KindOfArray)) {
    ad = Variant::GetArrayData(sacc);
  } else if (saccType == KindOfObject) {
    return f_array_key_exists(key, toArray(search));
  } else {
    throw_bad_type_exception("array_key_exists expects an array or an object; "
                           "false returned.");
    return false;
  }
  Variant::TypedValueAccessor kacc = key.getTypedAccessor();
  switch (Variant::GetAccessorType(kacc)) {
  case KindOfString:
  case KindOfStaticString: {
    int64_t n = 0;
    StringData *sd = Variant::GetStringData(kacc);
    if (sd->isStrictlyInteger(n)) {
      return ad->exists(n);
    }
    return ad->exists(StrNR(sd));
  }
  case KindOfInt64:
    return ad->exists(Variant::GetInt64(kacc));
  case KindOfUninit:
  case KindOfNull:
    return ad->exists(empty_string);
  default:
    break;
  }
  raise_warning("Array key should be either a string or an integer");
  return false;
}
Exemplo n.º 26
0
ArrayData *GlobalArrayWrapper::set(StringData* k, CVarRef v, bool copy) {
  m_globals->get(StrNR(k)).assignVal(v);
  return NULL;
}
Exemplo n.º 27
0
CachedUnit loadUnitNonRepoAuth(StringData* requestedPath,
                               const struct stat* statInfo,
                               OptLog& ent,
                               const Native::FuncTable& nativeFuncs,
                               const RepoOptions& options,
                               FileLoadFlags& flags) {
  LogTimer loadTime("load_ms", ent);
  if (strstr(requestedPath->data(), "://") != nullptr) {
    // URL-based units are not currently cached in memory, but the Repo still
    // caches them on disk.
    return createUnitFromUrl(requestedPath, nativeFuncs, flags);
  }

  rqtrace::EventGuard trace{"WRITE_UNIT"};

  // The string we're using as a key must be static, because we're using it as
  // a key in the cache (across requests).
  auto const path =
    makeStaticString(
      // XXX: it seems weird we have to do this even though we already ran
      // resolveVmInclude.
      (FileUtil::isAbsolutePath(requestedPath->toCppString())
       ?  String{requestedPath}
        : String(SourceRootInfo::GetCurrentSourceRoot()) + StrNR(requestedPath)
      ).get()
    );

  auto const rpath = [&] () -> const StringData* {
    if (RuntimeOption::CheckSymLink) {
      std::string rp = StatCache::realpath(path->data());
      if (rp.size() != 0) {
        if (rp.size() != path->size() ||
            memcmp(rp.data(), path->data(), rp.size())) {
          return makeStaticString(rp);
        }
      }
    }
    return path;
  }();

  Stream::Wrapper* w = nullptr;
  auto& cache = getNonRepoCache(rpath, w);

  assertx(
    !w || &cache != &s_nonRepoUnitCache ||
    !RuntimeOption::EvalUnixServerQuarantineUnits
  );

  // Freeing a unit while holding the tbb lock would cause a rank violation when
  // recycle-tc is enabled as reclaiming dead functions requires that the code
  // and metadata locks be acquired.
  Unit* releaseUnit = nullptr;
  SCOPE_EXIT { if (releaseUnit) delete releaseUnit; };

  auto const updateAndUnlock = [] (auto& cachedUnit, auto p) {
    auto old = cachedUnit.update_and_unlock(std::move(p));
    if (old) {
      // We don't need to do anything explicitly; the copy_ptr
      // destructor will take care of it.
      Treadmill::enqueue([unit_to_delete = std::move(old)] () {});
    }
  };

  auto cuptr = [&] {
    NonRepoUnitCache::const_accessor rpathAcc;

    cache.insert(rpathAcc, rpath);
    auto& cachedUnit = rpathAcc->second.cachedUnit;
    if (auto const tmp = cachedUnit.copy()) {
      if (!isChanged(tmp, statInfo, options)) {
        flags = FileLoadFlags::kHitMem;
        if (ent) ent->setStr("type", "cache_hit_readlock");
        return tmp;
      }
    }

    cachedUnit.lock_for_update();
    try {
      if (auto const tmp = cachedUnit.copy()) {
        if (!isChanged(tmp, statInfo, options)) {
          cachedUnit.unlock();
          flags = FileLoadFlags::kWaited;
          if (ent) ent->setStr("type", "cache_hit_writelock");
          return tmp;
        }
        if (ent) ent->setStr("type", "cache_stale");
      } else {
        if (ent) ent->setStr("type", "cache_miss");
      }

      trace.finish();
      auto const cu = createUnitFromFile(rpath, &releaseUnit, w, ent,
                                         nativeFuncs, options, flags);
      auto const isICE = cu.unit && cu.unit->isICE();
      auto p = copy_ptr<CachedUnitWithFree>(cu, statInfo, isICE, options);
      // Don't cache the unit if it was created in response to an internal error
      // in ExternCompiler. Such units represent transient events.
      if (UNLIKELY(isICE)) {
        cachedUnit.unlock();
        return p;
      }
      updateAndUnlock(cachedUnit, p);
      return p;
    } catch (...) {
      cachedUnit.unlock();
      throw;
    }
  }();

  auto const ret = cuptr->cu;

  if (!ret.unit || !ret.unit->isICE()) {
    if (path != rpath) {
      NonRepoUnitCache::const_accessor pathAcc;
      cache.insert(pathAcc, path);
      if (pathAcc->second.cachedUnit.get().get() != cuptr) {
        auto& cachedUnit = pathAcc->second.cachedUnit;
        cachedUnit.lock_for_update();
        updateAndUnlock(cachedUnit, std::move(cuptr));
      }
    }
  }

  return ret;
}
Variant NameValueTableWrapper::getKey(ssize_t pos) const {
  NameValueTable::Iterator iter(m_tab, pos);
  return iter.valid() ? Variant(StrNR(iter.curKey())) : uninit_null();
}
Exemplo n.º 29
0
TypedValue* ArrayData::nvGetCell(const StringData* key) const {
  TypedValue* tv = (TypedValue*)&get(StrNR(key), false);
  return LIKELY(tv != (TypedValue*)&null_variant) ? tvToCell(tv) :
         nvGetNotFound(key);
}
static inline StrNR ctxClassName() {
  Class* ctx = g_context->getContextClass();
  return ctx ? ctx->nameStr() : StrNR(staticEmptyString());
}