Exemple #1
0
bool objOffsetIsset(TypedValue& tvRef, ObjectData* base, const Variant& offset,
                    bool validate /* = true */) {
  auto exists = objOffsetExists(base, offset);

  // Unless we called ArrayObject::offsetExists, there's nothing more to do
  if (exists != OffsetExistsResult::IssetIfNonNull) {
    return (int)exists;
  }

  // For ArrayObject::offsetExists, we need to check the value at `offset`.
  // If it's null, then we return false.
  TypedValue tvResult;
  tvWriteUninit(&tvResult);

  // We can't call the offsetGet method on `base` because users aren't
  // expecting offsetGet to be called for `isset(...)` expressions, so call
  // the method on the base ArrayObject class.
  auto const method =
    SystemLib::s_ArrayObjectClass->lookupMethod(s_offsetGet.get());
  assert(method != nullptr);
  g_context->invokeFuncFew(&tvResult, method, base, nullptr, 1,
                           offset.asCell());
  auto const result = !isNullType(tvResult.m_type);
  tvRefcountedDecRef(&tvResult);
  return result;
}
Exemple #2
0
bool cellSame(Cell c1, Cell c2) {
  assert(cellIsPlausible(c1));
  assert(cellIsPlausible(c2));

  bool const null1 = isNullType(c1.m_type);
  bool const null2 = isNullType(c2.m_type);
  if (null1 && null2) return true;
  if (null1 || null2) return false;

  switch (c1.m_type) {
    case KindOfBoolean:
    case KindOfInt64:
      if (c2.m_type != c1.m_type) return false;
      return c1.m_data.num == c2.m_data.num;

    case KindOfDouble:
      if (c2.m_type != c1.m_type) return false;
      return c1.m_data.dbl == c2.m_data.dbl;

    case KindOfPersistentString:
    case KindOfString:
      if (!isStringType(c2.m_type)) return false;
      return c1.m_data.pstr->same(c2.m_data.pstr);

    case KindOfPersistentArray:
    case KindOfArray:
      if (!isArrayType(c2.m_type)) return false;
      return c1.m_data.parr->equal(c2.m_data.parr, true);

    case KindOfObject:
      return c2.m_type == KindOfObject &&
        c1.m_data.pobj == c2.m_data.pobj;

    case KindOfResource:
      return c2.m_type == KindOfResource &&
        c1.m_data.pres == c2.m_data.pres;

    case KindOfUninit:
    case KindOfNull:
    case KindOfRef:
    case KindOfClass:
      break;
  }
  not_reached();
}
Exemple #3
0
bool tvCoerceParamToNullableObjectInPlace(TypedValue* tv) {
  assert(tvIsPlausible(*tv));
  tvUnboxIfNeeded(tv);
  if (isNullType(tv->m_type)) {
    // See comment in tvCastToNullableObjectInPlace
    tv->m_data.pobj = nullptr;
    return true;
  }
  return tv->m_type == KindOfObject;
}
Exemple #4
0
//////////////////////////////////////////////////////////////////////////////
// class ImagickDraw
ALWAYS_INLINE
static void getAffineMatrixElement(
    const Array& array, const String& key, double& ret) {
  auto const value = array.rvalAt(key).unboxed();
  if (isNullType(value.type())) {
    IMAGICKDRAW_THROW(
      "AffineMatrix must contain keys: sx, rx, ry, sy, tx and ty");
  } else {
    ret = cellToDouble(value.tv());
  }
}
Exemple #5
0
NEVER_INLINE
APCHandle::Pair APCObject::ConstructSlow(ObjectData* objectData,
                                         ClassOrName name) {
  Array odProps;
  objectData->o_getArray(odProps);
  auto const propCount = odProps.size();

  auto size = sizeof(APCObject) + sizeof(Prop) * propCount;
  auto const apcObj = new (malloc_huge(size)) APCObject(name, propCount);
  if (!propCount) return {apcObj->getHandle(), size};

  auto prop = apcObj->props();
  for (ArrayIter it(odProps); !it.end(); it.next(), ++prop) {
    Variant key(it.first());
    assert(key.isString());
    auto const rval = it.secondRval();
    if (!isNullType(tvToCell(rval).type())) {
      auto val = APCHandle::Create(VarNR(rval.tv()), false,
                                   APCHandleLevel::Inner, true);
      prop->val = val.handle;
      size += val.size;
    } else {
      prop->val = nullptr;
    }

    const String& keySD = key.asCStrRef();

    if (!keySD.empty() && *keySD.data() == '\0') {
      int32_t subLen = keySD.find('\0', 1) + 1;
      String cls = keySD.substr(1, subLen - 2);
      if (cls.size() == 1 && cls[0] == '*') {
        // Protected.
        prop->ctx = nullptr;
      } else {
        // Private.
        auto* ctx = Unit::lookupClass(cls.get());
        if (ctx && ctx->attrs() & AttrUnique) {
          prop->ctx = ctx;
        } else {
          prop->ctx = makeStaticString(cls.get());
        }
      }
      prop->name = makeStaticString(keySD.substr(subLen));
    } else {
      prop->ctx = nullptr;
      prop->name = makeStaticString(keySD.get());
    }
  }
  assert(prop == apcObj->props() + propCount);

  return {apcObj->getHandle(), size};
}
Exemple #6
0
void tvCastToNullableObjectInPlace(TypedValue* tv) {
  if (isNullType(tv->m_type)) {
    // XXX(t3879280) This happens immediately before calling an extension
    // function that takes an optional Object argument. We want to end up
    // passing const Object& holding nullptr, so by clearing out m_data.pobj we
    // can unconditionally treat &tv->m_data.pobj as a const Object& in the
    // function being called. This violates the invariant that the value of
    // m_data doesn't matter in a KindOfNull TypedValue.
    tv->m_data.pobj = nullptr;
  } else {
    tvCastToObjectInPlace(tv);
  }
}
Exemple #7
0
bool MySQLStmtVariables::bind_params(MYSQL_STMT *stmt) {
  m_value_arr.clear();
  for (int i = 0; i < m_arr.size(); i++) {
    MYSQL_BIND *b = &m_vars[i];
    auto const var = m_arr.lvalAt(i).unboxed();
    Variant v;
    if (isNullType(var.type())) {
      *b->is_null = 1;
    } else {
      switch (b->buffer_type) {
        case MYSQL_TYPE_LONGLONG:
          {
            m_value_arr.push_back(cellToInt(var.tv()));
            b->buffer = m_value_arr.back().getInt64Data();
          }
          break;
        case MYSQL_TYPE_DOUBLE:
          {
            m_value_arr.push_back(tvCastToDouble(var.tv()));
            b->buffer = m_value_arr.back().getDoubleData();
          }
          break;
        case MYSQL_TYPE_STRING:
          {
            m_value_arr.push_back(tvCastToString(var.tv()));
            StringData *sd = m_value_arr.back().getStringData();
            b->buffer = (void *)sd->data();
            // FIXME: setting buffer_length will cause the destructor to free
            // memory owned by the string
            *b->length = sd->size();
          }
          break;
        case MYSQL_TYPE_LONG_BLOB:
          // The value are set using send_long_data so we don't have to do
          // anything here
          break;
        default:
          assertx(false);
      }
    }
  }

  return !mysql_stmt_bind_param(stmt, m_vars);
}