Exemple #1
0
static void unserializeProp(VariableUnserializer *uns,
                            ObjectData *obj, const String& key,
                            Class* ctx, const String& realKey,
                            int nProp) {
  // Do a two-step look up
  bool visible, accessible, unset;
  auto t = &tvAsVariant(obj->getProp(ctx, key.get(),
                                     visible, accessible, unset));
  assert(!unset);
  if (!t || !accessible) {
    // Dynamic property. If this is the first, and we're using MixedArray,
    // we need to pre-allocate space in the array to ensure the elements
    // dont move during unserialization.
    //
    // TODO(#2881866): this assumption means we can't do reallocations
    // when promoting kPackedKind -> kMixedKind.
    t = &obj->reserveProperties(nProp).lvalAt(realKey, AccessFlags::Key);
  }

  t->unserialize(uns);

  if (!RuntimeOption::EvalCheckRepoAuthDeserialize) return;
  if (!RuntimeOption::RepoAuthoritative) return;
  if (!Repo::get().global().HardPrivatePropInference) return;

  /*
   * We assume for performance reasons in repo authoriative mode that
   * we can see all the sets to private properties in a class.
   *
   * It's a hole in this if we don't check unserialization doesn't
   * violate what we've seen, which we handle by throwing if the repo
   * was built with this option.
   */
  auto const cls  = obj->getVMClass();
  auto const slot = cls->lookupDeclProp(key.get());
  if (UNLIKELY(slot == kInvalidSlot)) return;
  auto const repoTy = obj->getVMClass()->declPropRepoAuthType(slot);
  if (LIKELY(tvMatchesRepoAuthType(*t->asTypedValue(), repoTy))) {
    return;
  }

  auto msg = folly::format(
    "Property {} for class {} was deserialized with type ({}) that "
    "didn't match what we inferred in static analysis",
    key.data(),
    obj->getVMClass()->name()->data(),
    tname(t->asTypedValue()->m_type)
  ).str();
  throw Exception(msg);
}
Exemple #2
0
std::string getObjectConnectionName(
  ObjectData* obj,
  const void* target
) {
  Class* cls = obj->getVMClass();
  FTRACE(5, "HG: Getting connection name for type {} at {}\n",
    obj->getClassName().data(),
    obj
  );

  if (!supportsToArray(obj)) {
    return "";
  }

  auto arr = obj->toArray();
  bool is_packed = arr->isPacked();
  for (ArrayIter iter(arr); iter; ++iter) {
    auto first = iter.first();
    auto key = first.toString();
    auto key_tv = first.asTypedValue();
    auto val_tv = iter.secondRef().asTypedValue();

    if (key_tv->m_type == HPHP::KindOfString) {
      // If the key begins with a NUL, it's a private or protected property.
      // Read the class name from between the two NUL bytes.
      //
      // Note: Copied from object-data.cpp
      if (!key.empty() && key[0] == '\0') {
        int subLen = key.find('\0', 1) + 1;
        key = key.substr(subLen);
      }
    }

    FTRACE(5, "HG: ...Iterating over object key-val {}=>{}\n",
      key, tname(val_tv->m_type)
    );

    // We're only interested in the porperty name that points to our target
    if ((void*)val_tv->m_data.pobj != target) {
      continue;
    }

    bool is_declared =
        key_tv->m_type == HPHP::KindOfString &&
        cls->lookupDeclProp(key.get()) != kInvalidSlot;

    if (!is_declared && !is_packed) {
      return std::string("Key:" + key);
    } else if (is_packed) {
      return std::string("PropertyIndex");
    } else {
      return std::string("Property:" + key);
    }
  }

  return "";
}
Exemple #3
0
void ProxyArray::proxyAppend(void* data, uint32_t data_size, void** dest) {
  ArrayData * r;
  if (hasZvalValues()) {
    assert(data_size == sizeof(void*));
    int64_t k = 0;
    r = innerArr(this)->zAppend(*(RefData**)data, &k);
    if (dest) {
      *dest = (void*)(&r->nvGet(k)->m_data.pref);
    }
  } else {
    auto v = Variant(makeElementResource(data, data_size, dest));
    r = innerArr(this)->append(*v.asTypedValue(), false);
  }
  reseatable(this, r);
}
Exemple #4
0
ArrayData* StructArray::MakeUncounted(ArrayData* array) {
  auto structArray = asStructArray(array);
  // We don't need to copy the full capacity, since the array won't
  // change once it's uncounted.
  auto size = structArray->size();
  StructArray* result = createUncounted(structArray->shape(), size);
  result->m_hdr.init(HeaderKind::Struct, UncountedValue);
  result->m_sizeAndPos = array->m_sizeAndPos;
  auto const srcData = structArray->data();
  auto const stop    = srcData + size;
  auto targetData    = result->data();
  for (auto ptr = srcData; ptr != stop; ++ptr, ++targetData) {
    auto srcVariant = MixedArray::CreateVarForUncountedArray(tvAsCVarRef(ptr));
    tvCopy(*srcVariant.asTypedValue(),
           *targetData);
  }
  assert(result->m_pos == structArray->m_pos);
  assert(result->isUncounted());
  return result;
}
Exemple #5
0
Object APCObject::createObject() const {
  Object obj;

  const Class* klass;
  if (auto const c = m_cls.left()) {
    klass = c;
  } else {
    klass = Unit::loadClass(m_cls.right());
    if (!klass) {
      Logger::Error("APCObject::getObject(): Cannot find class %s",
                    m_cls.right()->data());
      return obj;
    }
  }
  obj = ObjectData::newInstance(const_cast<Class*>(klass));
  obj.get()->clearNoDestruct();

  auto prop = props();
  auto const propEnd = prop + m_propCount;
  for (; prop != propEnd; ++prop) {
    auto const key = prop->name;

    const Class* ctx = nullptr;
    if (prop->ctx.isNull()) {
      ctx = klass;
    } else {
      if (auto const cls = prop->ctx.left()) {
        ctx = cls;
      } else {
        ctx = Unit::lookupClass(prop->ctx.right());
        if (!ctx) continue;
      }
    }

    auto val = prop->val ? prop->val->toLocal() : init_null();
    obj->setProp(const_cast<Class*>(ctx), key, val.asTypedValue(), false);
  }

  obj->invokeWakeup();
  return obj;
}
Variant::~Variant() noexcept {
  tvRefcountedDecRef(asTypedValue());
  if (debug) {
    memset(this, kTVTrashFill2, sizeof(*this));
  }
}
Exemple #7
0
int Variant::getRefCount() const noexcept {
    return isRefcountedType(m_type) ? tvGetCount(asTypedValue()) : 1;
}