bool ConcurrentTableSharedStore::get(CStrRef key, Variant &value) { const StoreValue *sval; SharedVariant *svar = nullptr; ConditionalReadLock l(m_lock, !apcExtension::ConcurrentTableLockFree || m_lockingFlag); bool expired = false; bool promoteObj = false; { Map::const_accessor acc; if (!m_vars.find(acc, key.data())) { log_apc(std_apc_miss); return false; } else { sval = &acc->second; if (sval->expired()) { // Because it only has a read lock on the data, deletion from // expiration has to happen after the lock is released expired = true; } else { if (!sval->inMem()) { std::lock_guard<SmallLock> sval_lock(sval->lock); if (!sval->inMem()) { svar = unserialize(key, sval); if (!svar) return false; } else { svar = sval->var; } } else { svar = sval->var; } if (apcExtension::AllowObj && svar->is(KindOfObject)) { // Hold ref here for later promoting the object svar->incRef(); promoteObj = true; } value = svar->toLocal(); stats_on_get(key.get(), svar); } } } if (expired) { log_apc(std_apc_miss); eraseImpl(key, true); return false; } log_apc(std_apc_hit); if (promoteObj) { handlePromoteObj(key, svar, value); // release the extra ref svar->decRef(); } return true; }
UserStreamWrapper::UserStreamWrapper(CStrRef name, CStrRef clsname) : m_name(name) { m_cls = Unit::loadClass(clsname.get()); if (!m_cls) { throw InvalidArgumentException(0, "Undefined class '%s'", clsname.data()); } // There is a third param in Zend to stream_wrapper_register() which could // affect that when we add that param m_isLocal = true; }
bool f_defined(CStrRef name, bool autoload /* = true */) { if (!name.get()) return false; const char *data = name.data(); int len = name.length(); char *colon; if ((colon = (char*)memchr(data, ':', len)) && colon[1] == ':') { // class constant int classNameLen = colon - data; char *constantName = colon + 2; String className(data, classNameLen, CopyString); // translate "self" or "parent" if (className == "self") { String this_class = g_vmContext->getContextClassName(); if (this_class.empty()) { throw FatalErrorException("Cannot access self:: " "when no class scope is active"); } else { className = this_class; } } else if (className == "parent") { String parent_class = g_vmContext->getParentContextClassName(); if (parent_class.empty()) { throw FatalErrorException("Cannot access parent"); } else { className = parent_class; } } if (class_exists(className)) { // taking care of volatile class const ClassInfo *info; for (String parentClass = className; !parentClass.empty(); parentClass = info->getParentClass()) { info = ClassInfo::FindClass(parentClass); if (!info) { assert(false); } if (info->hasConstant(constantName)) return true; } return false; } else { return false; } } else { // system/uniquely defined scalar constant if (ClassInfo::FindConstant(name)) return true; if (g_vmContext->defined(name)) { return true; } if (!autoload || !AutoloadHandler::s_instance->autoloadConstant(name)) { return false; } return g_vmContext->defined(name); } }
int ThreadSharedVariant::getIndex(CStrRef key) { ASSERT(is(KindOfArray)); if (getIsVector()) return -1; StringData *sd = key.get(); if (RuntimeOption::ApcUseGnuMap) { StringDataToIntMap::const_iterator it = m_data.gnuMap->strMap->find(sd); if (it == m_data.gnuMap->strMap->end()) return -1; return it->second; } return m_data.map->indexOf(sd); }
void TaintWarning::WarnIfTainted(CStrRef s, const taint_t bit) { const TaintData& td = s.get()->getTaintDataRefConst(); if (!(td.getTaint() & bit)) { return; } bool force_warning = false; std::string buf, aux; buf = "Using a "; switch (bit) { case TAINT_BIT_HTML: buf += "HTML-unsafe (tainted)"; if (TaintTracer::IsTraceEnabled(TAINT_BIT_TRACE_HTML)) { force_warning = true; aux = TaintTracer::ExtractTrace(td.getTaintTrace()); } break; case TAINT_BIT_MUTATED: buf += "non-static (tainted)"; break; case TAINT_BIT_SQL: buf += "SQL-unsafe (tainted)"; break; case TAINT_BIT_SHELL: buf += "shell-unsafe (tainted)"; break; case TAINT_BIT_ALL: buf += "tainted"; break; default: return; } buf += " string!\n"; if (RuntimeOption::EnableTaintWarnings || force_warning) { buf += aux; buf += "\n"; buf += "---begin output---\n"; buf += s.c_str(); buf += "\n"; buf += "----end output----\n"; ZeroCount(bit); raise_warning(buf); } else { IncCount(bit); } }
bool f_defined(CStrRef name, bool autoload /* = true */) { if (!name.get()) return false; const char *data = name.data(); int len = name.length(); char *colon; if ((colon = (char*)memchr(data, ':', len)) && colon[1] == ':') { // class constant int classNameLen = colon - data; char *constantName = colon + 2; VM::Class* cls = getClassByName(data, classNameLen); if (cls) { String cnsName(constantName, data + len - constantName, CopyString); return cls->clsCnsGet(cnsName.get()); } return false; } else { return autoload ? VM::Unit::loadCns(name.get()) : VM::Unit::lookupCns(name.get()); } }
CVarRef ZendArray::get(CStrRef k, bool error /* = false */) const { StringData *key = k.get(); int64 prehash = key->hash(); Bucket *p = find(key->data(), key->size(), prehash); if (p) { return p->data; } if (error) { raise_notice("Undefined index: %s", k.data()); } return null_variant; }
Variant f_constant(CStrRef name) { if (!name.get()) return uninit_null(); const char *data = name.data(); int len = name.length(); // slice off starting backslash bool hadInitialBackslash = false; if (len > 0 && data[0] == '\\') { data += 1; len -= 1; hadInitialBackslash = true; } char *colon; if ((colon = (char*)memchr(data, ':', len)) && colon[1] == ':') { // class constant int classNameLen = colon - data; char *constantName = colon + 2; Class* cls = getClassByName(data, classNameLen); if (cls) { String cnsName(constantName, data + len - constantName, CopyString); TypedValue* tv = cls->clsCnsGet(cnsName.get()); if (tv) { return tvAsCVarRef(tv); } } raise_warning("Couldn't find constant %s", data); } else { TypedValue* cns; if (hadInitialBackslash) { String s(data, len, CopyString); cns = Unit::loadCns(s.get()); } else { cns = Unit::loadCns(name.get()); } if (cns) return tvAsVariant(cns); } return uninit_null(); }
void f_hphp_set_static_property(CStrRef cls, CStrRef prop, CVarRef value) { StringData* sd = cls.get(); Class* class_ = Unit::lookupClass(sd); if (class_ == nullptr) { String normName = normalizeNS(sd); if (normName) { return f_hphp_set_static_property(normName, prop, value); } else { raise_error("Non-existent class %s", sd->data()); } } VMRegAnchor _; bool visible, accessible; TypedValue* tv = class_->getSProp(arGetContextClass( g_vmContext->getFP()), prop.get(), visible, accessible); if (tv == nullptr) { raise_error("Class %s does not have a property named %s", cls.get()->data(), prop.get()->data()); } if (!visible || !accessible) { raise_error("Invalid access to class %s's property %s", cls.get()->data(), prop.get()->data()); } tvAsVariant(tv) = value; }
Array f_hphp_get_function_info(CStrRef name) { Array ret; const Func* func = Unit::loadFunc(name.get()); if (!func) return ret; ret.set(s_name, VarNR(func->name())); ret.set(s_closure, empty_string); // setting parameters and static variables set_function_info(ret, func); set_source_info(ret, func->unit()->filepath()->data(), func->line1(), func->line2()); return ret; }
Array vm_get_class_vars(CStrRef className) { HPHP::VM::Class* cls = HPHP::VM::Unit::lookupClass(className.get()); if (cls == NULL) { raise_error("Unknown class %s", className->data()); } cls->initialize(); const VM::Class::SProp* sPropInfo = cls->staticProperties(); const size_t numSProps = cls->numStaticProperties(); const VM::Class::Prop* propInfo = cls->declProperties(); const size_t numDeclProps = cls->numDeclProperties(); // The class' instance property initialization template is in different // places, depending on whether it has any request-dependent initializers // (i.e. constants) const VM::Class::PropInitVec& declPropInitVec = cls->declPropInit(); const VM::Class::PropInitVec* propVals = !cls->pinitVec().empty() ? cls->getPropData() : &declPropInitVec; ASSERT(propVals != NULL); ASSERT(propVals->size() == numDeclProps); // For visibility checks CallerFrame cf; HPHP::VM::Class* ctx = arGetContextClass(cf()); const ClassInfo* ctxCI = (ctx == NULL ? NULL : g_vmContext->findClassInfo(CStrRef(ctx->nameRef()))); ClassInfo::PropertyMap propMap; g_vmContext->findClassInfo(className)->getAllProperties(propMap); HphpArray* ret = NEW(HphpArray)(numDeclProps + numSProps); for (size_t i = 0; i < numDeclProps; ++i) { StringData* name = const_cast<StringData*>(propInfo[i].m_name); // Empty names are used for invisible/private parent properties; skip them if (name->size() == 0) continue; if (propMap[String(name)]->isVisible(ctxCI)) { const TypedValue* value = &((*propVals)[i]); ret->nvSet(name, value, false); } } for (size_t i = 0; i < numSProps; ++i) { bool vis, access; TypedValue* value = cls->getSProp(ctx, sPropInfo[i].m_name, vis, access); if (vis) { ret->nvSet(const_cast<StringData*>(sPropInfo[i].m_name), value, false); } } return ret; }
void VariableSerializer::write(CStrRef v) { if (m_type == APCSerialize && !v.isNull() && v->isStatic()) { union { char buf[8]; StringData *sd; } u; u.sd = v.get(); m_buf->append("S:"); m_buf->append(u.buf, 8); m_buf->append(';'); } else { v.serialize(this); } }
bool eval_invoke_file_hook(Variant &res, CStrRef path, bool once, LVariableTable* variables, const char *currentDir) { bool initial; HPHP::Eval::PhpFile* efile = g_vmContext->lookupPhpFile(path.get(), currentDir, &initial); HPHP::VM::Unit* u = nullptr; if (efile) u = efile->unit(); if (u == nullptr) { return false; } if (!once || initial) { g_vmContext->invokeUnit((TypedValue*)(&res), u); } return true; }
bool f_define(CStrRef name, CVarRef value, bool case_insensitive /* = false */) { if (case_insensitive) { raise_warning(Strings::CONSTANTS_CASE_SENSITIVE); } if (hhvm) { // TODO: Once we're inlining constants from hphpc this should // fatal or fail in some other way. return g_vmContext->setCns(name.get(), value, true); } else { // define() should be turned into constant definition by HPHP assert(false); return false; } }
Array f_get_class_constants(CStrRef class_name) { if (hhvm) { return vm_get_class_constants(class_name.get()); } const ClassInfo *cls = ClassInfo::FindClass(class_name); Array ret = Array::Create(); if (cls) { const ClassInfo::ConstantVec &constants = cls->getConstantsVec(); for (ClassInfo::ConstantVec::const_iterator iter = constants.begin(); iter != constants.end(); ++iter) { ret.set((*iter)->name, (*iter)->getValue()); } } return ret; }
static bool is_a_impl(CVarRef class_or_object, CStrRef class_name, bool allow_string, bool subclass_only) { if (class_or_object.isString() && !allow_string) { return false; } const Class* cls = get_cls(class_or_object); if (!cls) return false; if (cls->attrs() & AttrTrait) return false; const Class* other = lookup_class(class_name.get()); if (!other) return false; if (other->attrs() & AttrTrait) return false; if (other == cls) return !subclass_only; return cls->classof(other); }
bool f_trait_exists(CStrRef trait_name, bool autoload /* = true */) { if (hhvm) { return VM::Unit::classExists(trait_name.get(), autoload, VM::AttrTrait); } const ClassInfo *info = ClassInfo::FindClassInterfaceOrTrait(trait_name); if (info) { return info->getAttribute() & ClassInfo::IsTrait; } if (!autoload) return false; AutoloadHandler::s_instance->invokeHandler(trait_name); return f_trait_exists(trait_name, false); }
Variant f_get_class_vars(CStrRef className) { const Class* cls = Unit::loadClass(className.get()); if (!cls) { return false; } cls->initialize(); const Class::SProp* sPropInfo = cls->staticProperties(); const size_t numSProps = cls->numStaticProperties(); const Class::Prop* propInfo = cls->declProperties(); const size_t numDeclProps = cls->numDeclProperties(); // The class' instance property initialization template is in different // places, depending on whether it has any request-dependent initializers // (i.e. constants) const Class::PropInitVec& declPropInitVec = cls->declPropInit(); const Class::PropInitVec* propVals = !cls->pinitVec().empty() ? cls->getPropData() : &declPropInitVec; assert(propVals != NULL); assert(propVals->size() == numDeclProps); // For visibility checks CallerFrame cf; Class* ctx = arGetContextClass(cf()); ArrayInit arr(numDeclProps + numSProps); for (size_t i = 0; i < numDeclProps; ++i) { StringData* name = const_cast<StringData*>(propInfo[i].m_name); // Empty names are used for invisible/private parent properties; skip them assert(name->size() != 0); if (Class::IsPropAccessible(propInfo[i], ctx)) { const TypedValue* value = &((*propVals)[i]); arr.set(name, tvAsCVarRef(value), true /* isKey */); } } for (size_t i = 0; i < numSProps; ++i) { bool vis, access; TypedValue* value = cls->getSProp(ctx, sPropInfo[i].m_name, vis, access); if (access) { arr.set(const_cast<StringData*>(sPropInfo[i].m_name), tvAsCVarRef(value), true /* isKey */); } } return arr.toArray(); }
bool f_class_exists(CStrRef class_name, bool autoload /* = true */) { if (hhvm) { return VM::Unit::classExists(class_name.get(), autoload, VM::AttrNone); } const ClassInfo *info = ClassInfo::FindClassInterfaceOrTrait(class_name); if (info) { ClassInfo::Attribute attr = info->getAttribute(); return !(attr & (ClassInfo::IsInterface|ClassInfo::IsTrait)); } if (!autoload) return false; AutoloadHandler::s_instance->invokeHandler(class_name); return f_class_exists(class_name, false); }
/** * The Map::accessor here establishes a write lock, which means that other * threads, protected by read locks through Map::const_accessor, will not * read erased values from APC. * The ReadLock here is to sync with clear(), which only has a WriteLock, * not a specific accessor. */ bool ConcurrentTableSharedStore::eraseImpl(CStrRef key, bool expired) { if (key.isNull()) return false; ReadLock l(m_lock); Map::accessor acc; if (m_vars.find(acc, key.data())) { if (expired && !acc->second.expired()) { return false; } if (RuntimeOption::EnableAPCSizeStats) { SharedStoreStats::removeDirect(key.size(), acc->second.size); if (RuntimeOption::EnableAPCSizeGroup) { SharedStoreStats::onDelete(key.get(), acc->second.var, false); } } eraseAcc(acc); return true; } return false; }
bool eval_invoke_file_hook(Variant &res, CStrRef path, bool once, LVariableTable* variables, const char *currentDir) { if (hhvm) { bool initial; HPHP::Eval::PhpFile* efile = g_vmContext->lookupPhpFile(path.get(), currentDir, &initial); HPHP::VM::Unit* u = NULL; if (efile) u = efile->unit(); if (u == NULL) { return false; } if (!once || initial) { g_vmContext->invokeUnit((TypedValue*)(&res), u); } return true; } else { return RequestEvalState::includeFile(res, path, once, variables, currentDir); } }
Array vm_get_class_constants(CStrRef className) { HPHP::VM::Class* cls = HPHP::VM::Unit::lookupClass(className.get()); if (cls == NULL) { return NEW(HphpArray)(0); } size_t numConstants = cls->numConstants(); HphpArray* retVal = NEW(HphpArray)(numConstants); const VM::Class::Const* consts = cls->constants(); for (size_t i = 0; i < numConstants; i++) { // Note: hphpc doesn't include inherited constants in // get_class_constants(), so mimic that behavior if (consts[i].m_class == cls) { StringData* name = const_cast<StringData*>(consts[i].m_name); TypedValue* value = cls->clsCnsGet(consts[i].m_name); retVal->nvSet(name, value, false); } } return retVal; }
Variant f_get_called_class() { if (hhvm) { CallerFrame cf; ActRec* ar = cf(); if (ar == NULL) { return Variant(false); } if (ar->hasThis()) { ObjectData* obj = ar->getThis(); return obj->o_getClassName(); } else if (ar->hasClass()) { return ar->getClass()->preClass()->name()->data(); } else { return Variant(false); } } else { CStrRef cls = FrameInjection::GetStaticClassName( ThreadInfo::s_threadInfo.getNoCheck()); return cls.size() ? Variant(cls.get()) : Variant(false); } }
bool ConcurrentTableSharedStore::exists(CStrRef key) { bool stats = RuntimeOption::EnableStats && RuntimeOption::EnableAPCStats; bool statsFetch = RuntimeOption::EnableAPCSizeStats && RuntimeOption::EnableAPCFetchStats; const StoreValue *val; ReadLock l(m_lock); bool expired = false; { Map::const_accessor acc; if (!m_vars.find(acc, key.data())) { if (stats) ServerStats::Log("apc.miss", 1); return false; } else { val = &acc->second; if (val->expired()) { // Because it only has a read lock on the data, deletion from // expiration has to happen after the lock is released expired = true; } else { // No need toLocal() here, avoiding the copy if (statsFetch) { SharedStoreStats::onGet(key.get(), val->var); } } } } if (expired) { if (stats) { ServerStats::Log("apc.miss", 1); } eraseImpl(key, true); return false; } if (stats) { ServerStats::Log("apc.hit", 1); } return true; }
static int64 hphp_get_call_info_and_extra( CStrRef cls, CStrRef func, int64 &extra) { if (func.empty()) { throw_spl_exception("Invalid function name given"); } if (cls.empty()) { const CallInfo *cit; void *extrap; get_call_info_or_fail(cit, extrap, func); extra = (int64) extrap; return (int64) cit; } else { MethodCallPackage mcp; mcp.rootCls = cls.get(); mcp.name = &func; if (!get_call_info_static_method(mcp)) { throw_spl_exception("Could not find method %s for class %s", func.c_str(), cls.c_str()); } extra = (int64) mcp.extra; return (int64) mcp.ci; } }
DebuggerProxyPtr Debugger::GetProxy() { TRACE(2, "Debugger::GetProxy\n"); CStrRef sandboxId = g_context->getSandboxId(); return s_debugger.findProxy(sandboxId.get()); }
void Debugger::UnregisterSandbox(CStrRef id) { TRACE(2, "Debugger::UnregisterSandbox\n"); s_debugger.unregisterSandbox(id.get()); }
void rename_function(CStrRef old_name, CStrRef new_name) { g_vmContext->renameFunction(old_name.get(), new_name.get()); }
bool check_renamed_function(CStrRef name) { return g_vmContext->isFunctionRenameable(name.get()); }
StringName::StringName(CONSTRUCT_ARGS, CStrRef name, bool isSp /* = false */) : Name(CONSTRUCT_PASS), m_name(name.get()), m_isSp(isSp), m_sg(VariableIndex::isSuperGlobal(m_name)) { ASSERT(m_name->isStatic()); }