// Return true if the array satisfies requirement on the ArraySpec. static bool arrayFitsSpec(const ArrayData* arr, const ArraySpec spec) { if (spec == ArraySpec::Top) return true; if (auto const spec_kind = spec.kind()) { if (arr->kind() == spec_kind) return true; } if (auto const rat_type = spec.type()) { using A = RepoAuthType::Array; if (arr->empty() && rat_type->emptiness() != A::Empty::No) return true; if (arr->isVectorData()) { switch (rat_type->tag()) { case A::Tag::Packed: if (arr->size() != rat_type->size()) break; // fall through case A::Tag::PackedN: { int64_t k = 0; for ( ; k < arr->size(); ++k) { auto const specElemType = rat_type->tag() == A::Tag::Packed ? rat_type->packedElem(k) : rat_type->elemType(); if (!tvMatchesRepoAuthType(*(arr->get(k).asTypedValue()), specElemType)) { break; } } if (k == arr->size()) return true; break; } } } } return false; }
static void unserializeProp(VariableUnserializer* uns, ObjectData* obj, const String& key, Class* ctx, const String& realKey, int nProp) { // Do a two-step look up auto const lookup = obj->getProp(ctx, key.get()); Variant* t; if (!lookup.prop || !lookup.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); } else { t = &tvAsVariant(lookup.prop); } if (UNLIKELY(IS_REFCOUNTED_TYPE(t->getRawType()))) { uns->putInOverwrittenList(*t); } unserializeVariant(*t, uns); 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); }