bool ArrayData::hasInternalReference(PointerSet &vars, bool ds /* = false */) const { if (isSharedMap()) return false; for (ArrayIter iter(this); iter; ++iter) { CVarRef var = iter.secondRef(); if (var.isReferenced()) { Variant *pvar = var.getRefData(); if (vars.find(pvar) != vars.end()) { return true; } vars.insert(pvar); } if (var.isObject()) { ObjectData *pobj = var.getObjectData(); if (vars.find(pobj) != vars.end()) { return true; } vars.insert(pobj); if (ds && pobj->o_instanceof("Serializable")) { return true; } if (pobj->hasInternalReference(vars, ds)) { return true; } } else if (var.isArray() && var.getArrayData()->hasInternalReference(vars, ds)) { return true; } } return false; }
bool ArrayData::hasInternalReference(PointerSet &vars) const { if (supportValueRef()) { for (ArrayIter iter(this); iter; ++iter) { CVarRef var = iter.secondRef(); if (var.isReferenced()) { Variant *pvar = var.getVariantData(); if (vars.find(pvar) != vars.end()) { return true; } vars.insert(pvar); } if (var.isObject()) { ObjectData *pobj = var.getObjectData(); if (vars.find(pobj) != vars.end()) { return true; } vars.insert(pobj); if (pobj->o_toArray().get()->hasInternalReference(vars)) { return true; } } else if (var.isArray() && var.getArrayData()->hasInternalReference(vars)) { return true; } } } return false; }
static void php_array_replace_recursive(PointerSet &seen, bool check, Array &arr1, CArrRef arr2) { if (check) { if (seen.find((void*)arr1.get()) != seen.end()) { raise_warning("array_replace_recursive(): recursion detected"); return; } seen.insert((void*)arr1.get()); } for (ArrayIter iter(arr2); iter; ++iter) { Variant key = iter.first(); CVarRef value = iter.secondRef(); if (arr1.exists(key, true) && value.isArray()) { Variant &v = arr1.lvalAt(key, AccessFlags::Key); if (v.isArray()) { Array subarr1 = v.toArray(); const ArrNR& arr_value = value.toArrNR(); php_array_replace_recursive(seen, v.isReferenced(), subarr1, arr_value); v = subarr1; } else { arr1.set(key, value, true); } } else { arr1.lvalAt(key, AccessFlags::Key).setWithRef(value); } } if (check) { seen.erase((void*)arr1.get()); } }
static void php_array_merge_recursive(PointerSet &seen, bool check, Array &arr1, CArrRef arr2) { if (check) { if (seen.find((void*)arr1.get()) != seen.end()) { raise_warning("array_merge_recursive(): recursion detected"); return; } seen.insert((void*)arr1.get()); } for (ArrayIter iter(arr2); iter; ++iter) { Variant key(iter.first()); CVarRef value(iter.secondRef()); if (key.isNumeric()) { arr1.appendWithRef(value); } else if (arr1.exists(key, true)) { // There is no need to do toKey() conversion, for a key that is already // in the array. Variant &v = arr1.lvalAt(key, AccessFlags::Key); Array subarr1(v.toArray()->copy()); php_array_merge_recursive(seen, v.isReferenced(), subarr1, value.toArray()); v.unset(); // avoid contamination of the value that was strongly bound v = subarr1; } else { arr1.addLval(key, true).setWithRef(value); } } if (check) { seen.erase((void*)arr1.get()); } }
inline bool DataWalker::markVisited( void* pvar, DataFeature& features, PointerSet& visited) const { if (!visited.insert(pvar).second) { features.isCircular = true; return true; } return false; }
inline bool DataWalker::markVisited( void* pvar, DataFeature& features, PointerSet& visited) const { if (visited.find(pvar) != visited.end()) { features.m_circular = true; return true; } visited.insert(pvar); return false; }
bool ArrayData::hasInternalReference(PointerSet &vars, bool ds /* = false */) const { if (isSharedMap()) return false; for (ArrayIter iter(this); iter; ++iter) { CVarRef var = iter.secondRef(); if (var.isReferenced()) { Variant *pvar = var.getVariantData(); if (vars.find(pvar) != vars.end()) { return true; } vars.insert(pvar); } if (var.isObject()) { ObjectData *pobj = var.getObjectData(); if (vars.find(pobj) != vars.end()) { return true; } vars.insert(pobj); if (pobj->o_instanceof("Serializable")) { if (ds) { // We want to detect Serializable object as well return true; } else { // Serializable object does not have internal reference issue return false; } } if (pobj->o_toArray().get()->hasInternalReference(vars, ds)) { return true; } } else if (var.isArray() && var.getArrayData()->hasInternalReference(vars, ds)) { return true; } } return false; }
APCHandle* APCObject::MakeShared( ObjectData* objectData, size_t& size, bool inner, bool createFromSer) { if (!canOptimize(objectData)) { return createFromSer ? MakeShared(apc_serialize(objectData), size) : nullptr; } if (objectData->isCollection()) { return APCCollection::MakeShared(objectData, size, inner); } bool serialize = false; if (!inner) { PointerSet visited; visited.insert(reinterpret_cast<void*>(objectData)); traverseDataRecursive(objectData, [&](const Variant& var) { if (var.isReferenced()) { Variant *pvar = var.getRefData(); if (chekVisited(visited, pvar)) { serialize = true; return true; } } DataType type = var.getType(); if (type == KindOfObject) { auto data = var.getObjectData(); if (chekVisited(visited, reinterpret_cast<void*>(data))) { serialize = true; return true; } } else if (type == KindOfResource) { serialize = true; return true; } return false; } ); } if (serialize) { return createFromSer ? MakeShared(apc_serialize(objectData), size) : nullptr; } return Construct(objectData, size); }