hphp/runtime/base/runtime-option.cpp (2,519 lines of code) (raw):
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/runtime/base/runtime-option.h"
#include "hphp/runtime/base/autoload-handler.h"
#include "hphp/runtime/base/bespoke-array.h"
#include "hphp/runtime/base/builtin-functions.h"
#include "hphp/runtime/base/coeffects-config.h"
#include "hphp/runtime/base/config.h"
#include "hphp/runtime/base/crash-reporter.h"
#include "hphp/runtime/base/execution-context.h"
#include "hphp/runtime/base/extended-logger.h"
#include "hphp/runtime/base/file-util-defs.h"
#include "hphp/runtime/base/file-util.h"
#include "hphp/runtime/base/hphp-system.h"
#include "hphp/runtime/base/ini-setting.h"
#include "hphp/runtime/base/init-fini-node.h"
#include "hphp/runtime/base/memory-manager.h"
#include "hphp/runtime/base/plain-file.h"
#include "hphp/runtime/base/request-info.h"
#include "hphp/runtime/base/static-string-table.h"
#include "hphp/runtime/base/tv-refcount.h"
#include "hphp/runtime/base/zend-string.h"
#include "hphp/runtime/base/zend-url.h"
#include "hphp/runtime/ext/extension-registry.h"
#include "hphp/runtime/server/access-log.h"
#include "hphp/runtime/server/cli-server.h"
#include "hphp/runtime/server/files-match.h"
#include "hphp/runtime/server/satellite-server.h"
#include "hphp/runtime/server/virtual-host.h"
#include "hphp/runtime/vm/jit/code-cache.h"
#include "hphp/runtime/vm/jit/mcgen-translate.h"
#include "hphp/runtime/vm/treadmill.h"
#include "hphp/util/arch.h"
#include "hphp/util/atomic-vector.h"
#include "hphp/util/build-info.h"
#include "hphp/util/bump-mapper.h"
#include "hphp/util/cpuid.h"
#include "hphp/util/current-executable.h" // @donotremove
#include "hphp/util/file-cache.h"
#include "hphp/util/gzip.h"
#include "hphp/util/hardware-counter.h"
#include "hphp/util/hdf.h"
#include "hphp/util/light-process.h"
#include "hphp/util/log-file-flusher.h"
#include "hphp/util/logger.h"
#include "hphp/util/network.h"
#include "hphp/util/numa.h"
#include "hphp/util/process.h"
#include "hphp/util/service-data.h"
#include "hphp/util/stack-trace.h"
#include "hphp/util/text-util.h"
#include "hphp/util/zstd.h"
#include "hphp/zend/zend-string.h"
#include <cstdint>
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <stdexcept>
#include <vector>
#include <sstream>
#include <boost/algorithm/string/predicate.hpp>
#include <folly/CPortability.h>
#include <folly/Conv.h>
#include <folly/DynamicConverter.h>
#include <folly/FileUtil.h>
#include <folly/String.h>
#include <folly/portability/SysResource.h>
#include <folly/portability/SysTime.h>
#include <folly/portability/Unistd.h>
#if defined (__linux__) && defined (__aarch64__)
#include <sys/auxv.h>
#include <asm/hwcap.h>
#endif
#ifdef __APPLE__
#define st_mtim st_mtimespec
#define st_ctim st_ctimespec
#endif
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
bool RepoOptions::s_init{false};
RepoOptions RepoOptions::s_defaults;
namespace {
#ifdef FACEBOOK
const static bool s_PHP7_default = false;
#else
const static bool s_PHP7_default = true;
#endif
// PHP7 is off by default (false). s_PHP7_master is not a static member of
// RuntimeOption so that it's private to this file and not exposed -- it's a
// master switch only, and not to be used for any actual gating, use the more
// granular options instead. (It can't be a local since Config::Bind will take
// and store a pointer to it.)
static bool s_PHP7_master = s_PHP7_default;
std::vector<std::string> s_RelativeConfigs;
////////////////////////////////////////////////////////////////////////////////
void mangleForKey(bool b, std::string& s) { s += (b ? '1' : '0'); }
void mangleForKey(const RepoOptionsFlags::StringMap& map, std::string& s) {
s += folly::to<std::string>(map.size());
s += '\0';
for (auto const& par : map) {
s += par.first;
s += '\0';
s += par.second;
s += '\0';
}
}
void mangleForKey(const RepoOptionsFlags::StringVector& vec, std::string& s) {
s += folly::to<std::string>(vec.size());
s += '\0';
for (auto const& val : vec) {
s += val;
s += '\0';
}
}
void mangleForKey(const std::string& s1, std::string& s2) { s2 += s1; }
void hdfExtract(const Hdf& hdf, const char* name, bool& val, bool dv) {
val = hdf[name].configGetBool(dv);
}
void hdfExtract(const Hdf& hdf, const char* name, uint16_t& val, uint16_t dv) {
val = hdf[name].configGetUInt16(dv);
}
void hdfExtract(
const Hdf& hdf,
const char* name,
RepoOptionsFlags::StringMap& map,
const RepoOptionsFlags::StringMap& dv
) {
Hdf config = hdf[name];
if (config.exists() && !config.isEmpty()) config.configGet(map);
else map = dv;
}
void hdfExtract(
const Hdf& hdf,
const char* name,
RepoOptionsFlags::StringVector& vec,
const RepoOptionsFlags::StringVector& dv
) {
Hdf config = hdf[name];
if (config.exists() && !config.isEmpty()) config.configGet(vec);
else vec = dv;
}
void hdfExtract(
const Hdf& hdf,
const char* name,
std::string& val,
std::string dv
) {
val = hdf[name].configGetString(dv);
}
folly::dynamic toIniValue(bool b) {
return b ? "1" : "0";
}
folly::dynamic toIniValue(const RepoOptionsFlags::StringMap& map) {
folly::dynamic obj = folly::dynamic::object();
for (auto& kv : map) {
obj[kv.first] = kv.second;
}
return obj;
}
folly::dynamic toIniValue(const RepoOptionsFlags::StringVector& vec) {
folly::dynamic obj = folly::dynamic::array();
for (auto& val : vec) {
obj.push_back(val);
}
return obj;
}
folly::dynamic toIniValue(const std::string& str) {
return str;
}
struct CachedRepoOptions {
CachedRepoOptions() = default;
explicit CachedRepoOptions(RepoOptions&& opts)
: options(new RepoOptions(std::move(opts)))
{}
CachedRepoOptions(const CachedRepoOptions& opts)
: options(nullptr)
{
if (auto o = opts.options.load(std::memory_order_relaxed)) {
options.store(new RepoOptions(*o), std::memory_order_relaxed);
}
}
~CachedRepoOptions() {
Treadmill::enqueue([opt = options.exchange(nullptr)] { delete opt; });
}
CachedRepoOptions& operator=(const CachedRepoOptions& opts) {
auto const o = opts.options.load(std::memory_order_relaxed);
auto const old = options.exchange(o ? new RepoOptions(*o) : nullptr);
if (old) Treadmill::enqueue([old] { delete old; });
return *this;
}
static bool isChanged(const RepoOptions* opts, struct stat s) {
auto const o = opts->stat();
return
s.st_mtim.tv_sec != o.st_mtim.tv_sec ||
s.st_mtim.tv_nsec != o.st_mtim.tv_nsec ||
s.st_ctim.tv_sec != o.st_ctim.tv_sec ||
s.st_ctim.tv_nsec != o.st_ctim.tv_nsec ||
s.st_dev != o.st_dev ||
s.st_ino != o.st_ino;
}
const RepoOptions* update(RepoOptions&& opts) const {
auto const val = new RepoOptions(std::move(opts));
auto const old = options.exchange(val);
if (old) Treadmill::enqueue([old] { delete old; });
return val;
}
const RepoOptions* fetch(struct stat st) const {
auto const opts = options.load(std::memory_order_relaxed);
return opts && !isChanged(opts, st) ? opts : nullptr;
}
mutable std::atomic<RepoOptions*> options{nullptr};
};
struct RepoOptionCacheKey {
bool wrapped;
std::string filename;
};
struct RepoOptionCacheKeyCompare {
bool equal(const RepoOptionCacheKey& k1, const RepoOptionCacheKey& k2) const {
return k1.wrapped == k2.wrapped && k1.filename == k2.filename;
}
size_t hash(const RepoOptionCacheKey& k) const {
return std::hash<bool>()(k.wrapped) ^
hash_string_cs_unsafe(k.filename.c_str(), k.filename.size());
}
};
using RepoOptionCache = tbb::concurrent_hash_map<
RepoOptionCacheKey,
CachedRepoOptions,
RepoOptionCacheKeyCompare
>;
RepoOptionCache s_repoOptionCache;
template<class F>
bool walkDirTree(std::string fpath, F func) {
const char* filename = ".hhvmconfig.hdf";
do {
auto const off = fpath.rfind('/');
if (off == std::string::npos) return false;
fpath.resize(off);
fpath += '/';
fpath += filename;
if (func(fpath)) return true;
fpath.resize(off);
} while (!fpath.empty() && fpath != "/");
return false;
}
RDS_LOCAL(std::string, s_lastSeenRepoConfig);
}
ParserEnv RepoOptionsFlags::getParserEnvironment() const {
return ParserEnv {
true // codegen
, true // hhvm_compat_mode
, true // php5_compat_mode
, AllowNewAttributeSyntax
, EnableXHPClassModifier
, DisableXHPElementMangling
, false // disable_xhp_children_declarations
, DisallowFunAndClsMethPseudoFuncs
, true // interpret_soft_types_as_like_types
};
}
// Mapping must match HHBCFlags in compile.rs
std::uint32_t RepoOptionsFlags::getCompilerFlags() const {
std::uint32_t hhbc_flags = 0;
#define HHBC_FLAGS() \
SETFLAGS(LTRAssign, 0) \
SETFLAGS(UVS, 1) \
SETFLAGS(RuntimeOption::RepoAuthoritative, 4) \
SETFLAGS(RuntimeOption::EvalJitEnableRenameFunction, 5) \
SETFLAGS(RuntimeOption::EvalLogExternCompilerPerf, 6) \
SETFLAGS(RuntimeOption::EnableIntrinsicsExtension, 7) \
SETFLAGS(RuntimeOption::EvalEmitClsMethPointers, 10) \
SETFLAGS(RuntimeOption::EvalEmitMethCallerFuncPointers, 11) \
SETFLAGS(RuntimeOption::EvalEnableImplicitContext, 12) \
SETFLAGS(RuntimeOption::EvalFoldLazyClassKeys, 15)
#define SETFLAGS(flag, n) \
if (flag) {hhbc_flags |= 1 << n;}
HHBC_FLAGS()
#undef SETFLAGS
return hhbc_flags;
}
std::string RepoOptionsFlags::getAliasedNamespacesConfig() const {
folly::dynamic m_config = folly::dynamic::object();
m_config["hhvm.aliased_namespaces"] =
folly::dynamic::object("global_value", folly::toDynamic(AliasedNamespaces));
return folly::toJson(m_config);
}
std::uint32_t RepoOptionsFlags::getFactsFlags() const {
int32_t flags =
1 << 0 | //php5_compat_mode
1 << 1 | //hhvm_compat_mode
AllowNewAttributeSyntax << 2 |
EnableXHPClassModifier << 3 |
DisableXHPElementMangling << 4;
return flags;
}
std::uint32_t RepoOptionsFlags::getDeclFlags() const {
int32_t flags =
DisableXHPElementMangling << 0 |
1 << 1 | // interpret_soft_types_as_like_types
AllowNewAttributeSyntax << 2 |
EnableXHPClassModifier << 3 |
1 << 4 | //php5_compat_mode
1 << 5; //hhvm_compat_mode
return flags;
}
// Mapping must match ParserFlags in compile.rs
std::uint32_t RepoOptionsFlags::getParserFlags() const {
std::uint32_t parser_flags = 0;
#define PARSER_FLAGS() \
SETFLAGS(AbstractStaticProps, 0) \
SETFLAGS(AllowNewAttributeSyntax, 1) \
SETFLAGS(AllowUnstableFeatures, 2) \
SETFLAGS(ConstDefaultFuncArgs, 3) \
SETFLAGS(ConstStaticProps, 4) \
SETFLAGS(DisableLvalAsAnExpression, 8) \
SETFLAGS(DisallowInstMeth, 10) \
SETFLAGS(DisableXHPElementMangling, 11) \
SETFLAGS(DisallowFunAndClsMethPseudoFuncs, 12) \
SETFLAGS(DisallowFuncPtrsInConstants, 13) \
SETFLAGS(EnableEnumClasses,16) \
SETFLAGS(EnableXHPClassModifier,17) \
SETFLAGS(RuntimeOption::EnableClassLevelWhereClauses, 20) \
#define SETFLAGS(flag, n) \
if (flag) {parser_flags |= 1 << n;}
PARSER_FLAGS()
#undef SETFLAGS
return parser_flags;
}
const RepoOptions& RepoOptions::forFile(const char* path) {
tracing::BlockNoTrace _{"repo-options"};
if (!RuntimeOption::EvalEnablePerRepoOptions) return defaults();
std::string fpath{path};
if (boost::starts_with(fpath, "/:")) return defaults();
// Wrap filesystem accesses if needed to proxy info from cli server client.
Stream::Wrapper* wrapper = nullptr;
if (get_cli_ucred()) {
wrapper = Stream::getWrapperFromURI(path);
if (wrapper && !wrapper->isNormalFileStream()) wrapper = nullptr;
}
auto const wrapped_stat = [&](const char* path, struct stat* st) {
if (wrapper) return wrapper->stat(path, st);
return ::stat(path, st);
};
auto const wrapped_open = [&](const char* path) -> Optional<String> {
if (wrapper) {
if (auto const file = wrapper->open(path, "r", 0, nullptr)) {
return file->read();
}
return std::nullopt;
}
auto const fd = open(path, O_RDONLY);
if (fd < 0) return std::nullopt;
auto file = req::make<PlainFile>(fd);
return file->read();
};
auto const isParentOf = [] (const std::string& p1, const std::string& p2) {
return boost::starts_with(
boost::filesystem::path{p2},
boost::filesystem::path{p1}.parent_path()
);
};
// Fast path: we have an active request and it has cached a RepoOptions
// which has not been modified. This only works when the runtime option
// Eval.FatalOnParserOptionMismatch is set. It can cause us to miss out on
// configs that were added between the current directory and the source file.
// (Loading these configs would result in a fatal anyway with this option)
if (!g_context.isNull()) {
if (auto const opts = g_context->getRepoOptionsForRequest()) {
// If path() is empty we have the default() options, which means we have
// negatively cached the existance of a .hhvmconfig.hdf for this request.
if (opts->path().empty()) return *opts;
if (isParentOf(opts->path(), fpath)) {
struct stat st;
if (wrapped_stat(opts->path().data(), &st) == 0) {
if (!CachedRepoOptions::isChanged(opts, st)) return *opts;
}
}
}
}
auto const set = [&] (
RepoOptionCache::const_accessor& rpathAcc,
const std::string& path,
const struct stat& st
) -> const RepoOptions* {
*s_lastSeenRepoConfig = path;
if (auto const opts = rpathAcc->second.fetch(st)) {
return opts;
}
auto const contents = wrapped_open(path.data());
if (!contents) return nullptr;
RepoOptions newOpts{ contents->data(), path.data()};
newOpts.m_stat = st;
return rpathAcc->second.update(std::move(newOpts));
};
auto const test = [&] (const std::string& path) -> const RepoOptions* {
struct stat st;
RepoOptionCache::const_accessor rpathAcc;
const RepoOptionCacheKey key {(bool)wrapper, path};
if (!s_repoOptionCache.find(rpathAcc, key)) return nullptr;
if (wrapped_stat(path.data(), &st) != 0) {
s_repoOptionCache.erase(rpathAcc);
return nullptr;
}
return set(rpathAcc, path, st);
};
const RepoOptions* ret{nullptr};
// WARNING: when Eval.CachePerRepoOptionsPath we cache the last used path for
// RepoOptions per thread, and while we will detect changes to this
// file, and do a rescan in the event that it is deleted or doesn't
// match the current file being loaded, we will miss out on new
// configs that may be added. Since we expect to see a single config
// per repository we expect that this will be a reasonably safe,
// optimization.
if (RuntimeOption::EvalCachePerRepoOptionsPath) {
if (!s_lastSeenRepoConfig->empty() &&
isParentOf(*s_lastSeenRepoConfig, fpath)) {
if (auto const r = test(*s_lastSeenRepoConfig)) return *r;
s_lastSeenRepoConfig->clear();
}
// If the last seen path isn't set yet or is no longer accurate try checking
// other cached paths before falling back to the filesystem.
walkDirTree(fpath, [&] (const std::string& path) {
return (ret = test(path)) != nullptr;
});
}
if (ret) return *ret;
walkDirTree(fpath, [&] (const std::string& path) {
struct stat st;
if (wrapped_stat(path.data(), &st) != 0) return false;
RepoOptionCache::const_accessor rpathAcc;
const RepoOptionCacheKey key {(bool)wrapper, path};
s_repoOptionCache.insert(rpathAcc, key);
ret = set(rpathAcc, path, st);
return true;
});
return ret ? *ret : defaults();
}
void RepoOptions::calcCacheKey() {
std::string raw;
#define N(_, n, ...) mangleForKey(m_flags.n, raw);
#define P(_, n, ...) mangleForKey(m_flags.n, raw);
#define H(_, n, ...) mangleForKey(m_flags.n, raw);
#define E(_, n, ...) mangleForKey(m_flags.n, raw);
PARSERFLAGS()
AUTOLOADFLAGS()
#undef N
#undef P
#undef H
#undef E
m_flags.m_sha1 = SHA1{string_sha1(raw)};
}
std::string RepoOptions::toJSON() const {
return folly::toJson(toDynamic());
}
void RepoOptions::calcDynamic() {
m_cachedDynamic = folly::dynamic::object();
#define OUT(key, var) \
{ \
auto const ini_name = Config::IniName(key); \
auto const ini_value = toIniValue(var); \
folly::dynamic entry = folly::dynamic::object(); \
entry["global_value"] = ini_value; \
entry["local_value"] = ini_value; \
entry["access"] = 4; \
m_cachedDynamic[ini_name] = entry; \
}
#define N(_, n, ...) OUT(#n, m_flags.n)
#define P(_, n, ...) OUT("PHP7." #n, m_flags.n)
#define H(_, n, ...) OUT("Hack.Lang." #n, m_flags.n)
#define E(_, n, ...) OUT("Eval." #n, m_flags.n)
PARSERFLAGS()
AUTOLOADFLAGS();
#undef N
#undef P
#undef H
#undef E
#undef OUT
}
const RepoOptions& RepoOptions::defaults() {
always_assert(s_init);
return s_defaults;
}
void RepoOptions::filterNamespaces() {
for (auto it = m_flags.AliasedNamespaces.begin();
it != m_flags.AliasedNamespaces.end(); ) {
if (!is_valid_class_name(it->second)) {
Logger::Warning("Skipping invalid AliasedNamespace %s\n",
it->second.c_str());
it = m_flags.AliasedNamespaces.erase(it);
continue;
}
while (it->second.size() && it->second[0] == '\\') {
it->second = it->second.substr(1);
}
++it;
}
}
RepoOptions::RepoOptions(const char* str, const char* file) : m_path(file) {
always_assert(s_init);
Hdf config{};
config.fromString(str);
Hdf parserConfig = config["Parser"];
#define N(_, n, ...) hdfExtract(parserConfig, #n, m_flags.n, s_defaults.m_flags.n);
#define P(_, n, ...) hdfExtract(parserConfig, "PHP7." #n, m_flags.n, s_defaults.m_flags.n);
#define H(_, n, ...) hdfExtract(parserConfig, "Hack.Lang." #n, m_flags.n, s_defaults.m_flags.n);
#define E(_, n, ...) hdfExtract(parserConfig, "Eval." #n, m_flags.n, s_defaults.m_flags.n);
PARSERFLAGS();
#undef N
#undef P
#undef H
#undef E
Hdf autoloadConfig = config["Autoload"];
#define N(_, n, ...) hdfExtract(autoloadConfig, #n, m_flags.n, s_defaults.m_flags.n);
#define P(_, n, ...) hdfExtract(autoloadConfig, "PHP7." #n, m_flags.n, s_defaults.m_flags.n);
#define H(_, n, ...) hdfExtract(autoloadConfig, "Hack.Lang." #n, m_flags.n, \
s_defaults.m_flags.n);
#define E(_, n, ...) hdfExtract(autoloadConfig, "Eval." #n, m_flags.n, s_defaults.m_flags.n);
AUTOLOADFLAGS();
#undef N
#undef P
#undef H
#undef E
filterNamespaces();
calcCacheKey();
calcDynamic();
}
void RepoOptions::initDefaults(const Hdf& hdf, const IniSettingMap& ini) {
#define N(_, n, dv) Config::Bind(m_flags.n, ini, hdf, #n, dv);
#define P(_, n, dv) Config::Bind(m_flags.n, ini, hdf, "PHP7." #n, dv);
#define H(_, n, dv) Config::Bind(m_flags.n, ini, hdf, "Hack.Lang." #n, dv);
#define E(_, n, dv) Config::Bind(m_flags.n, ini, hdf, "Eval." #n, dv);
PARSERFLAGS()
AUTOLOADFLAGS()
#undef N
#undef P
#undef H
#undef E
filterNamespaces();
m_path.clear();
calcCacheKey();
}
void RepoOptions::setDefaults(const Hdf& hdf, const IniSettingMap& ini) {
always_assert(!s_init);
s_defaults.initDefaults(hdf, ini);
s_init = true;
}
///////////////////////////////////////////////////////////////////////////////
std::string RuntimeOption::BuildId;
std::string RuntimeOption::InstanceId;
std::string RuntimeOption::DeploymentId;
int64_t RuntimeOption::ConfigId = 0;
std::string RuntimeOption::PidFile = "www.pid";
bool RuntimeOption::ServerMode = false;
bool RuntimeOption::EnableHipHopSyntax = true;
bool RuntimeOption::EnableXHP = true;
bool RuntimeOption::EnableIntrinsicsExtension = false;
bool RuntimeOption::CheckSymLink = true;
bool RuntimeOption::TrustAutoloaderPath = false;
bool RuntimeOption::EnableArgsInBacktraces = true;
bool RuntimeOption::EnableZendIniCompat = true;
bool RuntimeOption::TimeoutsUseWallTime = true;
bool RuntimeOption::CheckFlushOnUserClose = true;
bool RuntimeOption::EvalAuthoritativeMode = false;
bool RuntimeOption::DumpPreciseProfData = true;
uint32_t RuntimeOption::EvalInitialStaticStringTableSize =
kDefaultInitialStaticStringTableSize;
uint32_t RuntimeOption::EvalInitialNamedEntityTableSize = 30000;
JitSerdesMode RuntimeOption::EvalJitSerdesMode{};
int RuntimeOption::ProfDataTTLHours = 24;
std::string RuntimeOption::ProfDataTag;
std::string RuntimeOption::EvalJitSerdesFile;
std::map<std::string, ErrorLogFileData> RuntimeOption::ErrorLogs = {
{Logger::DEFAULT, ErrorLogFileData()},
};
// these hold the DEFAULT logger
std::string RuntimeOption::LogFile;
std::string RuntimeOption::LogFileSymLink;
uint16_t RuntimeOption::LogFilePeriodMultiplier;
int RuntimeOption::LogHeaderMangle = 0;
bool RuntimeOption::AlwaysLogUnhandledExceptions = true;
bool RuntimeOption::AlwaysEscapeLog = true;
bool RuntimeOption::NoSilencer = false;
int RuntimeOption::ErrorUpgradeLevel = 0;
bool RuntimeOption::CallUserHandlerOnFatals = false;
bool RuntimeOption::ThrowExceptionOnBadMethodCall = true;
bool RuntimeOption::LogNativeStackOnOOM = true;
int RuntimeOption::RuntimeErrorReportingLevel =
static_cast<int>(ErrorMode::HPHP_ALL);
int RuntimeOption::ForceErrorReportingLevel = 0;
std::string RuntimeOption::ServerUser;
std::vector<std::string> RuntimeOption::TzdataSearchPaths;
int RuntimeOption::MaxSerializedStringSize = 64 * 1024 * 1024; // 64MB
int64_t RuntimeOption::NoticeFrequency = 1;
int64_t RuntimeOption::WarningFrequency = 1;
int RuntimeOption::RaiseDebuggingFrequency = 1;
int64_t RuntimeOption::SerializationSizeLimit = StringData::MaxSize;
std::string RuntimeOption::AccessLogDefaultFormat = "%h %l %u %t \"%r\" %>s %b";
std::map<std::string, AccessLogFileData> RuntimeOption::AccessLogs;
std::string RuntimeOption::AdminLogFormat = "%h %t %s %U";
std::string RuntimeOption::AdminLogFile;
std::string RuntimeOption::AdminLogSymLink;
std::map<std::string, AccessLogFileData> RuntimeOption::RPCLogs;
std::string RuntimeOption::Host;
std::string RuntimeOption::DefaultServerNameSuffix;
std::string RuntimeOption::ServerType = "proxygen";
std::string RuntimeOption::ServerIP;
std::string RuntimeOption::ServerFileSocket;
int RuntimeOption::ServerPort = 80;
int RuntimeOption::ServerPortFd = -1;
int RuntimeOption::ServerBacklog = 128;
int RuntimeOption::ServerConnectionLimit = 0;
int RuntimeOption::ServerThreadCount = 50;
int RuntimeOption::ServerQueueCount = 50;
int RuntimeOption::ServerIOThreadCount = 1;
int RuntimeOption::ServerHighQueueingThreshold = 60;
bool RuntimeOption::ServerLegacyBehavior = true;
int RuntimeOption::ServerHugeThreadCount = 0;
int RuntimeOption::ServerHugeStackKb = 384;
int RuntimeOption::ServerSchedPolicy = -1;
int RuntimeOption::ServerSchedPriority = 0;
uint32_t RuntimeOption::ServerLoopSampleRate = 0;
int RuntimeOption::ServerWarmupThrottleRequestCount = 0;
int RuntimeOption::ServerWarmupThrottleThreadCount = 0;
int RuntimeOption::ServerThreadDropCacheTimeoutSeconds = 0;
int RuntimeOption::ServerThreadJobLIFOSwitchThreshold = INT_MAX;
int RuntimeOption::ServerThreadJobMaxQueuingMilliSeconds = -1;
bool RuntimeOption::AlwaysDecodePostDataDefault = true;
bool RuntimeOption::ServerThreadDropStack = false;
bool RuntimeOption::ServerHttpSafeMode = false;
bool RuntimeOption::ServerStatCache = false;
bool RuntimeOption::ServerFixPathInfo = false;
bool RuntimeOption::ServerAddVaryEncoding = true;
bool RuntimeOption::ServerLogSettingsOnStartup = false;
bool RuntimeOption::ServerLogReorderProps = false;
bool RuntimeOption::ServerForkEnabled = true;
bool RuntimeOption::ServerForkLogging = false;
bool RuntimeOption::ServerWarmupConcurrently = false;
bool RuntimeOption::ServerDedupeWarmupRequests = false;
int RuntimeOption::ServerWarmupThreadCount = 1;
int RuntimeOption::ServerExtendedWarmupThreadCount = 1;
unsigned RuntimeOption::ServerExtendedWarmupRepeat = 1;
unsigned RuntimeOption::ServerExtendedWarmupDelaySeconds = 60;
std::vector<std::string> RuntimeOption::ServerWarmupRequests;
std::vector<std::string> RuntimeOption::ServerExtendedWarmupRequests;
std::string RuntimeOption::ServerCleanupRequest;
int RuntimeOption::ServerInternalWarmupThreads = 0;
boost::container::flat_set<std::string>
RuntimeOption::ServerHighPriorityEndPoints;
bool RuntimeOption::ServerExitOnBindFail;
int RuntimeOption::PageletServerThreadCount = 0;
int RuntimeOption::PageletServerHugeThreadCount = 0;
int RuntimeOption::PageletServerThreadDropCacheTimeoutSeconds = 0;
int RuntimeOption::PageletServerQueueLimit = 0;
bool RuntimeOption::PageletServerThreadDropStack = false;
int RuntimeOption::RequestTimeoutSeconds = 0;
int RuntimeOption::PspTimeoutSeconds = 0;
int RuntimeOption::PspCpuTimeoutSeconds = 0;
int64_t RuntimeOption::MaxRequestAgeFactor = 0;
int64_t RuntimeOption::RequestMemoryMaxBytes =
std::numeric_limits<int64_t>::max();
int64_t RuntimeOption::RequestHugeMaxBytes = 0;
int64_t RuntimeOption::ImageMemoryMaxBytes = 0;
int RuntimeOption::ServerGracefulShutdownWait = 0;
bool RuntimeOption::ServerHarshShutdown = true;
bool RuntimeOption::ServerEvilShutdown = true;
bool RuntimeOption::ServerKillOnTimeout = true;
bool RuntimeOption::Server503OnShutdownAbort = false;
int RuntimeOption::ServerPreShutdownWait = 0;
int RuntimeOption::ServerShutdownListenWait = 0;
int RuntimeOption::ServerShutdownEOMWait = 0;
int RuntimeOption::ServerPrepareToStopTimeout = 0;
int RuntimeOption::ServerPartialPostStatusCode = -1;
bool RuntimeOption::StopOldServer = false;
int RuntimeOption::OldServerWait = 30;
int RuntimeOption::CacheFreeFactor = 50;
int64_t RuntimeOption::ServerRSSNeededMb = 4096;
int64_t RuntimeOption::ServerCriticalFreeMb = 512;
std::vector<std::string> RuntimeOption::ServerNextProtocols;
bool RuntimeOption::ServerEnableH2C = false;
int RuntimeOption::BrotliCompressionEnabled = -1;
int RuntimeOption::BrotliChunkedCompressionEnabled = -1;
int RuntimeOption::BrotliCompressionMode = 0;
int RuntimeOption::BrotliCompressionQuality = 6;
int RuntimeOption::BrotliCompressionLgWindowSize = 20;
int RuntimeOption::ZstdCompressionEnabled = -1;
int RuntimeOption::ZstdCompressionLevel = 3;
int RuntimeOption::ZstdWindowLog = 0;
int RuntimeOption::ZstdChecksumRate = 0;
int RuntimeOption::GzipCompressionLevel = 3;
int RuntimeOption::GzipMaxCompressionLevel = 9;
bool RuntimeOption::EnableKeepAlive = true;
bool RuntimeOption::ExposeHPHP = true;
bool RuntimeOption::ExposeXFBServer = false;
bool RuntimeOption::ExposeXFBDebug = false;
std::string RuntimeOption::XFBDebugSSLKey;
int RuntimeOption::ConnectionTimeoutSeconds = -1;
bool RuntimeOption::EnableOutputBuffering = false;
std::string RuntimeOption::OutputHandler;
bool RuntimeOption::ImplicitFlush = false;
bool RuntimeOption::EnableEarlyFlush = true;
bool RuntimeOption::ForceChunkedEncoding = false;
int64_t RuntimeOption::MaxPostSize = 100;
int64_t RuntimeOption::LowestMaxPostSize = LLONG_MAX;
bool RuntimeOption::AlwaysPopulateRawPostData = false;
int64_t RuntimeOption::UploadMaxFileSize = 100;
std::string RuntimeOption::UploadTmpDir = "/tmp";
bool RuntimeOption::EnableFileUploads = true;
bool RuntimeOption::EnableUploadProgress = false;
int64_t RuntimeOption::MaxFileUploads = 20;
int RuntimeOption::Rfc1867Freq = 256 * 1024;
std::string RuntimeOption::Rfc1867Prefix = "vupload_";
std::string RuntimeOption::Rfc1867Name = "video_ptoken";
bool RuntimeOption::ExpiresActive = true;
int RuntimeOption::ExpiresDefault = 2592000;
std::string RuntimeOption::DefaultCharsetName = "";
bool RuntimeOption::ForceServerNameToHeader = false;
bool RuntimeOption::PathDebug = false;
int64_t RuntimeOption::RequestBodyReadLimit = -1;
bool RuntimeOption::EnableSSL = false;
int RuntimeOption::SSLPort = 443;
int RuntimeOption::SSLPortFd = -1;
std::string RuntimeOption::SSLCertificateFile;
std::string RuntimeOption::SSLCertificateKeyFile;
std::string RuntimeOption::SSLCertificateDir;
std::string RuntimeOption::SSLTicketSeedFile;
bool RuntimeOption::TLSDisableTLS1_2 = false;
std::string RuntimeOption::TLSClientCipherSpec;
bool RuntimeOption::EnableSSLWithPlainText = false;
int RuntimeOption::SSLClientAuthLevel = 0;
std::string RuntimeOption::SSLClientCAFile = "";
std::string RuntimeOption::ClientAuthAclIdentity;
std::string RuntimeOption::ClientAuthAclAction;
bool RuntimeOption::ClientAuthFailClose = false;
uint32_t RuntimeOption::SSLClientAuthLoggingSampleRatio = 0;
uint32_t RuntimeOption::ClientAuthSuccessLogSampleRatio = 0;
uint32_t RuntimeOption::ClientAuthFailureLogSampleRatio = 0;
uint32_t RuntimeOption::ClientAuthLogSampleBase = 100;
std::vector<std::shared_ptr<VirtualHost>> RuntimeOption::VirtualHosts;
std::shared_ptr<IpBlockMap> RuntimeOption::IpBlocks;
std::vector<std::shared_ptr<SatelliteServerInfo>>
RuntimeOption::SatelliteServerInfos;
bool RuntimeOption::AllowRunAsRoot = false; // Allow running hhvm as root.
int RuntimeOption::XboxServerThreadCount = 10;
int RuntimeOption::XboxServerMaxQueueLength = INT_MAX;
int RuntimeOption::XboxServerInfoMaxRequest = 500;
int RuntimeOption::XboxServerInfoDuration = 120;
std::string RuntimeOption::XboxServerInfoReqInitFunc;
std::string RuntimeOption::XboxServerInfoReqInitDoc;
bool RuntimeOption::XboxServerInfoAlwaysReset = false;
bool RuntimeOption::XboxServerLogInfo = false;
std::string RuntimeOption::XboxProcessMessageFunc = "xbox_process_message";
std::string RuntimeOption::XboxPassword;
std::set<std::string> RuntimeOption::XboxPasswords;
std::string RuntimeOption::SourceRoot = Process::GetCurrentDirectory() + '/';
std::vector<std::string> RuntimeOption::IncludeSearchPaths;
std::map<std::string, std::string> RuntimeOption::IncludeRoots;
std::map<std::string, std::string> RuntimeOption::AutoloadRoots;
bool RuntimeOption::AutoloadEnabled;
std::string RuntimeOption::AutoloadDBPath;
std::string RuntimeOption::AutoloadDBPerms{"0644"};
std::string RuntimeOption::AutoloadDBGroup;
std::string RuntimeOption::AutoloadLogging;
std::vector<std::string> RuntimeOption::AutoloadExcludedRepos;
bool RuntimeOption::AutoloadLoggingAllowPropagation;
bool RuntimeOption::AutoloadRethrowExceptions = true;
std::string RuntimeOption::FileCache;
std::string RuntimeOption::DefaultDocument;
std::string RuntimeOption::GlobalDocument;
std::string RuntimeOption::ErrorDocument404;
bool RuntimeOption::ForbiddenAs404 = false;
std::string RuntimeOption::ErrorDocument500;
std::string RuntimeOption::FatalErrorMessage;
std::string RuntimeOption::FontPath;
bool RuntimeOption::EnableStaticContentFromDisk = true;
bool RuntimeOption::EnableOnDemandUncompress = true;
bool RuntimeOption::EnableStaticContentMMap = true;
bool RuntimeOption::Utf8izeReplace = true;
std::string RuntimeOption::RequestInitFunction;
std::string RuntimeOption::RequestInitDocument;
std::string RuntimeOption::AutoPrependFile;
std::string RuntimeOption::AutoAppendFile;
bool RuntimeOption::SafeFileAccess = false;
std::vector<std::string> RuntimeOption::AllowedDirectories;
std::set<std::string> RuntimeOption::AllowedFiles;
hphp_string_imap<std::string> RuntimeOption::StaticFileExtensions;
hphp_string_imap<std::string> RuntimeOption::PhpFileExtensions;
std::set<std::string> RuntimeOption::ForbiddenFileExtensions;
std::vector<std::shared_ptr<FilesMatch>> RuntimeOption::FilesMatches;
bool RuntimeOption::WhitelistExec = false;
bool RuntimeOption::WhitelistExecWarningOnly = false;
std::vector<std::string> RuntimeOption::AllowedExecCmds;
bool RuntimeOption::UnserializationWhitelistCheck = false;
bool RuntimeOption::UnserializationWhitelistCheckWarningOnly = true;
int64_t RuntimeOption::UnserializationBigMapThreshold = 1 << 16;
std::string RuntimeOption::TakeoverFilename;
std::string RuntimeOption::AdminServerIP;
int RuntimeOption::AdminServerPort = 0;
int RuntimeOption::AdminThreadCount = 1;
bool RuntimeOption::AdminServerEnableSSLWithPlainText = false;
bool RuntimeOption::AdminServerStatsNeedPassword = true;
std::string RuntimeOption::AdminPassword;
std::set<std::string> RuntimeOption::AdminPasswords;
std::set<std::string> RuntimeOption::HashedAdminPasswords;
std::string RuntimeOption::AdminDumpPath;
std::string RuntimeOption::ProxyOriginRaw;
int RuntimeOption::ProxyPercentageRaw = 0;
int RuntimeOption::ProxyRetry = 3;
bool RuntimeOption::UseServeURLs;
std::set<std::string> RuntimeOption::ServeURLs;
bool RuntimeOption::UseProxyURLs;
std::set<std::string> RuntimeOption::ProxyURLs;
std::vector<std::string> RuntimeOption::ProxyPatterns;
bool RuntimeOption::AlwaysUseRelativePath = false;
int RuntimeOption::HttpDefaultTimeout = 30;
int RuntimeOption::HttpSlowQueryThreshold = 5000; // ms
bool RuntimeOption::NativeStackTrace = false;
bool RuntimeOption::ServerErrorMessage = false;
bool RuntimeOption::RecordInput = false;
bool RuntimeOption::ClearInputOnSuccess = true;
std::string RuntimeOption::ProfilerOutputDir = "/tmp";
std::string RuntimeOption::CoreDumpEmail;
bool RuntimeOption::CoreDumpReport = true;
std::string RuntimeOption::CoreDumpReportDirectory =
#if defined(HPHP_OSS)
"/tmp";
#else
"/var/tmp/cores";
#endif
std::string RuntimeOption::StackTraceFilename;
int RuntimeOption::StackTraceTimeout = 0; // seconds; 0 means unlimited
std::string RuntimeOption::RemoteTraceOutputDir = "/tmp";
std::set<std::string, stdltistr> RuntimeOption::TraceFunctions;
bool RuntimeOption::EnableStats = false;
bool RuntimeOption::EnableAPCStats = false;
bool RuntimeOption::EnableWebStats = false;
bool RuntimeOption::EnableMemoryStats = false;
bool RuntimeOption::EnableSQLStats = false;
bool RuntimeOption::EnableSQLTableStats = false;
bool RuntimeOption::EnableNetworkIOStatus = false;
std::string RuntimeOption::StatsXSL;
std::string RuntimeOption::StatsXSLProxy;
uint32_t RuntimeOption::StatsSlotDuration = 10 * 60; // 10 minutes
uint32_t RuntimeOption::StatsMaxSlot = 12 * 6; // 12 hours
int64_t RuntimeOption::MaxSQLRowCount = 0;
int64_t RuntimeOption::SocketDefaultTimeout = 60;
bool RuntimeOption::LockCodeMemory = false;
int RuntimeOption::MaxArrayChain = INT_MAX;
bool RuntimeOption::WarnOnCollectionToArray = false;
bool RuntimeOption::UseDirectCopy = false;
#if FOLLY_SANITIZE
bool RuntimeOption::DisableSmallAllocator = true;
#else
bool RuntimeOption::DisableSmallAllocator = false;
#endif
std::map<std::string, std::string> RuntimeOption::ServerVariables;
std::map<std::string, std::string> RuntimeOption::EnvVariables;
std::string RuntimeOption::LightProcessFilePrefix = "./lightprocess";
int RuntimeOption::LightProcessCount = 0;
int64_t RuntimeOption::HeapSizeMB = 4096; // 4gb
int64_t RuntimeOption::HeapResetCountBase = 1;
int64_t RuntimeOption::HeapResetCountMultiple = 2;
int64_t RuntimeOption::HeapLowWaterMark = 16;
int64_t RuntimeOption::HeapHighWaterMark = 1024;
uint64_t RuntimeOption::DisableCallUserFunc = 0;
uint64_t RuntimeOption::DisableCallUserFuncArray = 0;
uint64_t RuntimeOption::DisableConstant = 0;
bool RuntimeOption::EnableClassLevelWhereClauses = false;
std::string RuntimeOption::WatchmanRootSocket;
std::string RuntimeOption::WatchmanDefaultSocket;
#ifdef HHVM_DYNAMIC_EXTENSION_DIR
std::string RuntimeOption::ExtensionDir = HHVM_DYNAMIC_EXTENSION_DIR;
#else
std::string RuntimeOption::ExtensionDir = "";
#endif
std::vector<std::string> RuntimeOption::Extensions;
std::vector<std::string> RuntimeOption::DynamicExtensions;
std::string RuntimeOption::DynamicExtensionPath = ".";
int RuntimeOption::CheckCLIClientCommands = 0;
int RuntimeOption::CheckIntOverflow = 0;
HackStrictOption
RuntimeOption::StrictArrayFillKeys = HackStrictOption::OFF;
// defaults set when the INI option is bound - values below are irrelevant.
bool RuntimeOption::LookForTypechecker = false;
bool RuntimeOption::AutoTypecheck = false;
bool RuntimeOption::PHP7_EngineExceptions = false;
bool RuntimeOption::PHP7_NoHexNumerics = false;
bool RuntimeOption::PHP7_Builtins = false;
bool RuntimeOption::PHP7_Substr = false;
bool RuntimeOption::PHP7_DisallowUnsafeCurlUploads = false;
const std::string& RuntimeOption::GetServerPrimaryIPv4() {
static std::string serverPrimaryIPv4 = GetPrimaryIPv4();
return serverPrimaryIPv4;
}
const std::string& RuntimeOption::GetServerPrimaryIPv6() {
static std::string serverPrimaryIPv6 = GetPrimaryIPv6();
return serverPrimaryIPv6;
}
static inline std::string regionSelectorDefault() {
return "tracelet";
}
static inline bool pgoDefault() {
#ifdef HHVM_NO_DEFAULT_PGO
return false;
#else
return true;
#endif
}
static inline bool eagerGcDefault() {
#ifdef HHVM_EAGER_GC
return true;
#else
return false;
#endif
}
static inline bool enableGcDefault() {
return RuntimeOption::EvalEagerGC;
}
static inline uint64_t pgoThresholdDefault() {
return debug ? 2 : 2000;
}
static inline bool alignMacroFusionPairs() {
switch (getProcessorFamily()) {
case ProcessorFamily::Intel_SandyBridge:
case ProcessorFamily::Intel_IvyBridge:
case ProcessorFamily::Intel_Haswell:
case ProcessorFamily::Intel_Broadwell:
case ProcessorFamily::Intel_Skylake:
case ProcessorFamily::Intel_Cooperlake:
return true;
case ProcessorFamily::Unknown:
return false;
}
return false;
}
static inline bool armLseDefault() {
#if defined (__linux__) && defined (__aarch64__) && defined (HWCAP_ATOMICS)
return (getauxval(AT_HWCAP) & HWCAP_ATOMICS) != 0;
#else
return false;
#endif
}
static inline bool evalJitDefault() {
#ifdef _MSC_VER
return false;
#else
return true;
#endif
}
static inline bool reuseTCDefault() {
return hhvm_reuse_tc && !RuntimeOption::RepoAuthoritative;
}
static inline bool useFileBackedArenaDefault() {
return RuntimeOption::RepoAuthoritative &&
RuntimeOption::ServerExecutionMode();
}
static inline bool hugePagesSoundNice() {
return RuntimeOption::ServerExecutionMode();
}
static inline uint32_t hotTextHugePagesDefault() {
if (!hugePagesSoundNice()) return 0;
return arch() == Arch::ARM ? 12 : 8;
}
static inline std::string reorderPropsDefault() {
if (isJitDeserializing()) {
return "countedness-hotness";
}
return debug ? "alphabetical" : "countedness";
}
static inline uint32_t profileRequestsDefault() {
return debug ? std::numeric_limits<uint32_t>::max() : 2500;
}
static inline uint32_t profileBCSizeDefault() {
return debug ? std::numeric_limits<uint32_t>::max()
: RuntimeOption::EvalJitConcurrently ? 3750000
: 4300000;
}
static inline uint32_t resetProfCountersDefault() {
return RuntimeOption::EvalJitPGORacyProfiling
? std::numeric_limits<uint32_t>::max()
: RuntimeOption::EvalJitConcurrently ? 250 : 1000;
}
static inline int retranslateAllRequestDefault() {
return RuntimeOption::ServerExecutionMode() ? 1000000 : 0;
}
static inline int retranslateAllSecondsDefault() {
return RuntimeOption::ServerExecutionMode() ? 180 : 0;
}
static inline bool pgoLayoutSplitHotColdDefault() {
return arch() != Arch::ARM;
}
static inline bool layoutPrologueSplitHotColdDefault() {
return arch() != Arch::ARM;
}
Optional<folly::fs::path> RuntimeOption::GetHomePath(
const folly::StringPiece user) {
auto homePath = folly::fs::path{RuntimeOption::SandboxHome}
/ folly::fs::path{user};
if (folly::fs::is_directory(homePath)) {
return {std::move(homePath)};
}
if (!RuntimeOption::SandboxFallback.empty()) {
homePath = folly::fs::path{RuntimeOption::SandboxFallback}
/ folly::fs::path{user};
if (folly::fs::is_directory(homePath)) {
return {std::move(homePath)};
}
}
return {};
}
std::string RuntimeOption::GetDefaultUser() {
if (SandboxDefaultUserFile.empty()) return {};
folly::fs::path file{SandboxDefaultUserFile};
if (!folly::fs::is_regular_file(file)) return {};
std::string user;
if (!folly::readFile(file.c_str(), user) || user.empty()) return {};
return user;
}
bool RuntimeOption::ReadPerUserSettings(const folly::fs::path& confFileName,
IniSettingMap& ini, Hdf& config) {
try {
Config::ParseConfigFile(confFileName.native(), ini, config, false);
return true;
} catch (HdfException& e) {
Logger::Error("%s ignored: %s", confFileName.native().c_str(),
e.getMessage().c_str());
return false;
}
}
std::string RuntimeOption::getTraceOutputFile() {
return folly::sformat("{}/hphp.{}.log",
RuntimeOption::RemoteTraceOutputDir, (int64_t)getpid());
}
const uint64_t kEvalVMStackElmsDefault =
#if defined(VALGRIND) && !FOLLY_SANITIZE
0x800
#else
0x4000
#endif
;
constexpr uint32_t kEvalVMInitialGlobalTableSizeDefault = 512;
constexpr uint64_t kJitRelocationSizeDefault = 1 << 20;
static const bool kJitTimerDefault =
#ifdef ENABLE_JIT_TIMER_DEFAULT
true
#else
false
#endif
;
using std::string;
#define F(type, name, def) \
type RuntimeOption::Eval ## name = type(def);
EVALFLAGS();
#undef F
hphp_string_imap<TypedValue> RuntimeOption::ConstantFunctions;
bool RuntimeOption::RecordCodeCoverage = false;
std::string RuntimeOption::CodeCoverageOutputFile;
std::string RuntimeOption::RepoPath;
RepoMode RuntimeOption::RepoLocalMode = RepoMode::ReadOnly;
std::string RuntimeOption::RepoLocalPath;
RepoMode RuntimeOption::RepoCentralMode = RepoMode::ReadWrite;
std::string RuntimeOption::RepoCentralPath;
int32_t RuntimeOption::RepoCentralFileMode;
std::string RuntimeOption::RepoCentralFileUser;
std::string RuntimeOption::RepoCentralFileGroup;
std::string RuntimeOption::RepoJournal = "delete";
bool RuntimeOption::RepoAllowFallbackPath = true;
bool RuntimeOption::RepoCommit = true;
bool RuntimeOption::RepoDebugInfo = true;
bool RuntimeOption::RepoLitstrLazyLoad = true;
// Missing: RuntimeOption::RepoAuthoritative's physical location is
// perf-sensitive.
bool RuntimeOption::RepoLocalReadaheadConcurrent = false;
int64_t RuntimeOption::RepoLocalReadaheadRate = 0;
uint32_t RuntimeOption::RepoBusyTimeoutMS = 15000;
bool RuntimeOption::HHProfEnabled = false;
bool RuntimeOption::HHProfActive = false;
bool RuntimeOption::HHProfAccum = false;
bool RuntimeOption::HHProfRequest = false;
bool RuntimeOption::SandboxMode = false;
std::string RuntimeOption::SandboxPattern;
std::string RuntimeOption::SandboxHome;
std::string RuntimeOption::SandboxFallback;
std::string RuntimeOption::SandboxConfFile;
std::map<std::string, std::string> RuntimeOption::SandboxServerVariables;
bool RuntimeOption::SandboxFromCommonRoot = false;
std::string RuntimeOption::SandboxDirectoriesRoot;
std::string RuntimeOption::SandboxLogsRoot;
std::string RuntimeOption::SandboxDefaultUserFile;
std::string RuntimeOption::SandboxHostAlias;
bool RuntimeOption::EnableHphpdDebugger = false;
bool RuntimeOption::EnableVSDebugger = false;
int RuntimeOption::VSDebuggerListenPort = -1;
std::string RuntimeOption::VSDebuggerDomainSocketPath;
bool RuntimeOption::VSDebuggerNoWait = false;
bool RuntimeOption::EnableDebuggerColor = true;
bool RuntimeOption::EnableDebuggerPrompt = true;
bool RuntimeOption::EnableDebuggerServer = false;
bool RuntimeOption::EnableDebuggerUsageLog = false;
bool RuntimeOption::DebuggerDisableIPv6 = false;
std::string RuntimeOption::DebuggerServerIP;
int RuntimeOption::DebuggerServerPort = 8089;
std::string RuntimeOption::DebuggerDefaultSandboxPath;
std::string RuntimeOption::DebuggerStartupDocument;
int RuntimeOption::DebuggerSignalTimeout = 1;
std::string RuntimeOption::DebuggerAuthTokenScriptBin;
std::string RuntimeOption::DebuggerSessionAuthScriptBin;
std::string RuntimeOption::SendmailPath = "sendmail -t -i";
std::string RuntimeOption::MailForceExtraParameters;
int64_t RuntimeOption::PregBacktraceLimit = 1000000;
int64_t RuntimeOption::PregRecursionLimit = 100000;
bool RuntimeOption::EnablePregErrorLog = true;
bool RuntimeOption::SimpleXMLEmptyNamespaceMatchesAll = false;
bool RuntimeOption::EnableHotProfiler = true;
int RuntimeOption::ProfilerTraceBuffer = 2000000;
double RuntimeOption::ProfilerTraceExpansion = 1.2;
int RuntimeOption::ProfilerMaxTraceBuffer = 0;
#ifdef FACEBOOK
bool RuntimeOption::EnableFb303Server = false;
int RuntimeOption::Fb303ServerPort = 0;
std::string RuntimeOption::Fb303ServerIP;
int RuntimeOption::Fb303ServerThreadStackSizeMb = 8;
int RuntimeOption::Fb303ServerWorkerThreads = 1;
int RuntimeOption::Fb303ServerPoolThreads = 1;
#endif
double RuntimeOption::XenonPeriodSeconds = 0.0;
uint32_t RuntimeOption::XenonRequestFreq = 1;
bool RuntimeOption::XenonForceAlwaysOn = false;
bool RuntimeOption::StrobelightEnabled = false;
bool RuntimeOption::TrackPerUnitMemory = false;
bool RuntimeOption::SetProfileNullThisObject = true;
bool RuntimeOption::ApplySecondaryQueuePenalty = false;
std::map<std::string, std::string> RuntimeOption::CustomSettings;
#ifdef NDEBUG
#ifdef ALWAYS_ASSERT
const StaticString s_hhvm_build_type("Release with asserts");
#else
const StaticString s_hhvm_build_type("Release");
#endif
#else
const StaticString s_hhvm_build_type("Debug");
#endif
///////////////////////////////////////////////////////////////////////////////
static void setResourceLimit(int resource, const IniSetting::Map& ini,
const Hdf& rlimit, const char* nodeName) {
if (!Config::GetString(ini, rlimit, nodeName).empty()) {
struct rlimit rl;
getrlimit(resource, &rl);
rl.rlim_cur = Config::GetInt64(ini, rlimit, nodeName);
if (rl.rlim_max < rl.rlim_cur) {
rl.rlim_max = rl.rlim_cur;
}
int ret = setrlimit(resource, &rl);
if (ret) {
Logger::Error("Unable to set %s to %" PRId64 ": %s (%d)",
nodeName, (int64_t)rl.rlim_cur,
folly::errnoStr(errno).c_str(), errno);
}
}
}
static void normalizePath(std::string &path) {
if (!path.empty()) {
if (path[path.length() - 1] == '/') {
path = path.substr(0, path.length() - 1);
}
if (path[0] != '/') {
path = std::string("/") + path;
}
}
}
static String todayDate() {
time_t rawtime;
struct tm timeinfo;
char buf[256];
time(&rawtime);
localtime_r(&rawtime, &timeinfo);
strftime(buf, sizeof(buf), "%Y-%m-%d", &timeinfo);
return buf;
}
static bool matchShard(
bool enableShards,
const std::string& hostname,
const IniSetting::Map& ini, Hdf hdfPattern,
std::vector<std::string>& messages
) {
if (!hdfPattern.exists("Shard")) return true;
if (!enableShards) {
hdfPattern["Shard"].setVisited();
hdfPattern["ShardCount"].setVisited();
hdfPattern["ShardSalt"].setVisited();
return false;
}
auto const shard = Config::GetInt64(ini, hdfPattern, "Shard", -1, false);
auto const nshards =
Config::GetInt64(ini, hdfPattern, "ShardCount", 100, false);
if (shard < 0 || shard >= nshards) {
messages.push_back(folly::sformat("Invalid value for Shard: {}", shard));
return true;
}
auto input = hostname;
if (hdfPattern.exists("ShardSalt")) {
auto salt = Config::GetString(ini, hdfPattern, "ShardSalt", "", false);
salt = string_replace(salt, "%{date}", todayDate()).toCppString();
input += salt;
}
auto const md5 = Md5Digest(input.data(), input.size());
uint32_t seed{0};
memcpy(&seed, &md5.digest[0], 4);
// This shift is to match the behavior of sharding in chef which appears to
// have an off-by-one bug:
// seed = Digest::MD5.hexdigest(seed_input)[0...7].to_i(16)
seed = ntohl(seed) >> 4;
messages.push_back(folly::sformat(
"Checking Shard = {}; Input = {}; Seed = {}; ShardCount = {}; Value = {}",
shard, input, seed, nshards, seed % nshards
));
return seed % nshards <= shard;
}
// A machine can belong to a tier, which can overwrite
// various settings, even if they are set in the same
// hdf file. However, CLI overrides still win the day over
// everything.
static std::vector<std::string> getTierOverwrites(IniSetting::Map& ini,
Hdf& config) {
// Machine metrics
string hostname, tier, task, cpu, tiers, tags;
{
hostname = Config::GetString(ini, config, "Machine.name");
if (hostname.empty()) {
hostname = Process::GetHostName();
}
tier = Config::GetString(ini, config, "Machine.tier");
task = Config::GetString(ini, config, "Machine.task");
cpu = Config::GetString(ini, config, "Machine.cpu");
if (cpu.empty()) {
cpu = Process::GetCPUModel();
}
tiers = Config::GetString(ini, config, "Machine.tiers");
if (!tiers.empty()) {
if (!folly::readFile(tiers.c_str(), tiers)) {
tiers.clear();
}
}
tags = Config::GetString(ini, config, "Machine.tags");
if (!tags.empty()) {
if (!folly::readFile(tags.c_str(), tags)) {
tags.clear();
}
}
}
auto const checkPatterns = [&] (Hdf hdf) {
// Check the patterns using "&" rather than "&&" so they all get
// evaluated; otherwise with multiple patterns, if an earlier
// one fails to match, the later one is reported as unused.
return
Config::matchHdfPattern(hostname, ini, hdf, "machine") &
Config::matchHdfPattern(tier, ini, hdf, "tier") &
Config::matchHdfPattern(task, ini, hdf, "task") &
Config::matchHdfPattern(tiers, ini, hdf, "tiers", "m") &
Config::matchHdfPattern(tags, ini, hdf, "tags", "m") &
Config::matchHdfPattern(cpu, ini, hdf, "cpu");
};
std::vector<std::string> messages;
auto enableShards = true;
// Tier overwrites
{
for (Hdf hdf = config["Tiers"].firstChild(); hdf.exists();
hdf = hdf.next()) {
if (messages.empty()) {
messages.emplace_back(folly::sformat(
"Matching tiers using: "
"machine='{}', tier='{}', task='{}', "
"cpu='{}', tiers='{}', tags='{}'",
hostname, tier, task, cpu, tiers, tags));
}
// Check the patterns using "&" rather than "&&" so they all get
// evaluated; otherwise with multiple patterns, if an earlier
// one fails to match, the later one is reported as unused.
if (checkPatterns(hdf) &
(!hdf.exists("exclude") || !checkPatterns(hdf["exclude"])) &
matchShard(enableShards, hostname, ini, hdf, messages)) {
messages.emplace_back(folly::sformat(
"Matched tier: {}", hdf.getName()));
if (enableShards && hdf["DisableShards"].configGetBool()) {
messages.emplace_back("Sharding is disabled.");
enableShards = false;
}
if (hdf.exists("clear")) {
std::vector<std::string> list;
hdf["clear"].configGet(list);
for (auto const& s : list) {
config.remove(s);
}
}
config.copy(hdf["overwrite"]);
// no break here, so we can continue to match more overwrites
}
// Avoid lint errors about unvisited nodes when the tier does not match.
hdf["DisableShards"].setVisited();
hdf["clear"].setVisited();
hdf["overwrite"].setVisited();
}
}
return messages;
}
void RuntimeOption::ReadSatelliteInfo(
const IniSettingMap& ini,
const Hdf& hdf,
std::vector<std::shared_ptr<SatelliteServerInfo>>& infos,
std::string& xboxPassword,
std::set<std::string>& xboxPasswords) {
auto ss_callback = [&] (const IniSettingMap &ini_ss, const Hdf &hdf_ss,
const std::string &ini_ss_key) {
auto satellite = std::make_shared<SatelliteServerInfo>(ini_ss, hdf_ss,
ini_ss_key);
infos.push_back(satellite);
if (satellite->getType() == SatelliteServer::Type::KindOfRPCServer) {
xboxPassword = satellite->getPassword();
xboxPasswords = satellite->getPasswords();
}
};
Config::Iterate(ss_callback, ini, hdf, "Satellites");
}
extern void initialize_apc();
void RuntimeOption::Load(
IniSetting::Map& ini, Hdf& config,
const std::vector<std::string>& iniClis /* = std::vector<std::string>() */,
const std::vector<std::string>& hdfClis /* = std::vector<std::string>() */,
std::vector<std::string>* messages /* = nullptr */,
std::string cmd /* = "" */) {
// Intialize the memory manager here because various settings and
// initializations that we do here need it
tl_heap.getCheck();
// Get the ini (-d) and hdf (-v) strings, which may override some
// of options that were set from config files. We also do these
// now so we can override Tier.*.[machine | tier | cpu] on the
// command line, along with any fields within a Tier (e.g.,
// CoreFileSize)
for (auto& istr : iniClis) {
Config::ParseIniString(istr, ini);
}
for (auto& hstr : hdfClis) {
Config::ParseHdfString(hstr, config);
}
// See if there are any Tier-based overrides
auto m = getTierOverwrites(ini, config);
if (messages) *messages = std::move(m);
// RelativeConfigs can be set by commandline flags and tier overwrites, they
// may also contain tier overwrites. They are, however, only included once, so
// relative configs may not specify other relative configs which must to be
// loaded. If RelativeConfigs is modified while loading configs an error is
// raised, but we defer doing so until the logger is initialized below. If a
// relative config cannot be found it is silently skipped (this is to allow
// configs to be conditionally applied to scripts based on their location). By
// reading the "hhvm.relative_configs" ini setting at runtime it is possible
// to determine which configs were actually loaded.
std::string relConfigsError;
Config::Bind(s_RelativeConfigs, ini, config, "RelativeConfigs");
if (!cmd.empty() && !s_RelativeConfigs.empty()) {
String strcmd(cmd, CopyString);
Process::InitProcessStatics();
auto const currentDir = Process::CurrentWorkingDirectory.data();
std::vector<std::string> newConfigs;
auto const original = s_RelativeConfigs;
for (auto& str : original) {
if (str.empty()) continue;
std::string fullpath;
auto const found = FileUtil::runRelative(
str, strcmd, currentDir,
[&] (const String& f) {
if (access(f.data(), R_OK) == 0) {
fullpath = f.toCppString();
FTRACE_MOD(Trace::facts, 3, "Parsing {}\n", fullpath);
Config::ParseConfigFile(fullpath, ini, config);
return true;
}
return false;
}
);
if (found) newConfigs.emplace_back(std::move(fullpath));
}
if (!newConfigs.empty()) {
auto m2 = getTierOverwrites(ini, config);
if (messages) *messages = std::move(m2);
if (s_RelativeConfigs != original) {
relConfigsError = folly::sformat(
"RelativeConfigs node was modified while loading configs from [{}] "
"to [{}]",
folly::join(", ", original),
folly::join(", ", s_RelativeConfigs)
);
}
}
s_RelativeConfigs.swap(newConfigs);
} else {
s_RelativeConfigs.clear();
}
// Then get the ini and hdf cli strings again, in case the tier overwrites
// overrode any non-tier based command line option we set. The tier-based
// command line overwrites will already have been set in the call above.
// This extra call is for the other command line options that may have been
// overridden by a tier, but shouldn't have been.
for (auto& istr : iniClis) {
Config::ParseIniString(istr, ini);
}
for (auto& hstr : hdfClis) {
Config::ParseHdfString(hstr, config);
}
Config::Bind(PidFile, ini, config, "PidFile", "www.pid");
Config::Bind(DeploymentId, ini, config, "DeploymentId");
{
static std::string deploymentIdOverride;
Config::Bind(deploymentIdOverride, ini, config, "DeploymentIdOverride");
if (!deploymentIdOverride.empty()) {
RuntimeOption::DeploymentId = deploymentIdOverride;
}
}
{
// Config ID
Config::Bind(ConfigId, ini, config, "ConfigId", 0);
auto configIdCounter = ServiceData::createCounter("vm.config.id");
configIdCounter->setValue(ConfigId);
}
{
// Logging
auto setLogLevel = [](const std::string& value) {
// ini parsing treats "None" as ""
if (value == "None" || value == "") {
Logger::LogLevel = Logger::LogNone;
} else if (value == "Error") {
Logger::LogLevel = Logger::LogError;
} else if (value == "Warning") {
Logger::LogLevel = Logger::LogWarning;
} else if (value == "Info") {
Logger::LogLevel = Logger::LogInfo;
} else if (value == "Verbose") {
Logger::LogLevel = Logger::LogVerbose;
} else {
return false;
}
return true;
};
auto str = Config::GetString(ini, config, "Log.Level");
if (!str.empty()) {
setLogLevel(str);
}
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"hhvm.log.level", IniSetting::SetAndGet<std::string>(
setLogLevel,
[]() {
switch (Logger::LogLevel) {
case Logger::LogNone:
return "None";
case Logger::LogError:
return "Error";
case Logger::LogWarning:
return "Warning";
case Logger::LogInfo:
return "Info";
case Logger::LogVerbose:
return "Verbose";
}
return "";
}
));
Config::Bind(Logger::UseLogFile, ini, config, "Log.UseLogFile", true);
Config::Bind(LogFile, ini, config, "Log.File");
Config::Bind(LogFileSymLink, ini, config, "Log.SymLink");
Config::Bind(LogFilePeriodMultiplier, ini,
config, "Log.PeriodMultiplier", 0);
if (Logger::UseLogFile && RuntimeOption::ServerExecutionMode()) {
RuntimeOption::ErrorLogs[Logger::DEFAULT] =
ErrorLogFileData(LogFile, LogFileSymLink, LogFilePeriodMultiplier);
}
if (Config::GetBool(ini, config, "Log.AlwaysPrintStackTraces")) {
Logger::SetTheLogger(Logger::DEFAULT, new ExtendedLogger());
ExtendedLogger::EnabledByDefault = true;
}
Config::Bind(Logger::LogHeader, ini, config, "Log.Header");
Config::Bind(Logger::LogNativeStackTrace, ini, config,
"Log.NativeStackTrace", true);
Config::Bind(Logger::UseSyslog, ini, config, "Log.UseSyslog", false);
Config::Bind(Logger::UseRequestLog, ini, config, "Log.UseRequestLog",
false);
Config::Bind(Logger::AlwaysEscapeLog, ini, config, "Log.AlwaysEscapeLog",
true);
Config::Bind(Logger::UseCronolog, ini, config, "Log.UseCronolog", false);
Config::Bind(Logger::MaxMessagesPerRequest, ini,
config, "Log.MaxMessagesPerRequest", -1);
Config::Bind(LogFileFlusher::DropCacheChunkSize, ini,
config, "Log.DropCacheChunkSize", 1 << 20);
Config::Bind(RuntimeOption::LogHeaderMangle, ini, config,
"Log.HeaderMangle", 0);
Config::Bind(AlwaysLogUnhandledExceptions, ini,
config, "Log.AlwaysLogUnhandledExceptions",
true);
Config::Bind(NoSilencer, ini, config, "Log.NoSilencer");
Config::Bind(RuntimeErrorReportingLevel, ini,
config, "Log.RuntimeErrorReportingLevel",
static_cast<int>(ErrorMode::HPHP_ALL));
Config::Bind(ForceErrorReportingLevel, ini,
config, "Log.ForceErrorReportingLevel", 0);
Config::Bind(AccessLogDefaultFormat, ini, config,
"Log.AccessLogDefaultFormat", "%h %l %u %t \"%r\" %>s %b");
auto parseLogs = [] (const Hdf &config, const IniSetting::Map& ini,
const std::string &name,
std::map<std::string, AccessLogFileData> &logs) {
auto parse_logs_callback = [&] (const IniSetting::Map &ini_pl,
const Hdf &hdf_pl,
const std::string &ini_pl_key) {
string logName = hdf_pl.exists() && !hdf_pl.isEmpty()
? hdf_pl.getName()
: ini_pl_key;
string fname = Config::GetString(ini_pl, hdf_pl, "File", "", false);
if (!fname.empty()) {
string symlink = Config::GetString(ini_pl, hdf_pl, "SymLink", "",
false);
string format = Config::GetString(ini_pl, hdf_pl, "Format",
AccessLogDefaultFormat, false);
auto periodMultiplier = Config::GetUInt16(ini_pl, hdf_pl,
"PeriodMultiplier",
0, false);
logs[logName] = AccessLogFileData(fname, symlink,
format, periodMultiplier);
}
};
Config::Iterate(parse_logs_callback, ini, config, name);
};
parseLogs(config, ini, "Log.Access", AccessLogs);
RPCLogs = AccessLogs;
parseLogs(config, ini, "Log.RPC", RPCLogs);
Config::Bind(AdminLogFormat, ini, config, "Log.AdminLog.Format",
"%h %t %s %U");
Config::Bind(AdminLogFile, ini, config, "Log.AdminLog.File");
Config::Bind(AdminLogSymLink, ini, config, "Log.AdminLog.SymLink");
}
{
// Error Handling
Config::Bind(ErrorUpgradeLevel, ini, config, "ErrorHandling.UpgradeLevel",
0);
Config::Bind(MaxSerializedStringSize, ini,
config, "ErrorHandling.MaxSerializedStringSize",
64 * 1024 * 1024);
Config::Bind(CallUserHandlerOnFatals, ini,
config, "ErrorHandling.CallUserHandlerOnFatals", false);
Config::Bind(ThrowExceptionOnBadMethodCall, ini,
config, "ErrorHandling.ThrowExceptionOnBadMethodCall", true);
Config::Bind(LogNativeStackOnOOM, ini,
config, "ErrorHandling.LogNativeStackOnOOM", false);
Config::Bind(NoticeFrequency, ini, config, "ErrorHandling.NoticeFrequency",
1);
Config::Bind(WarningFrequency, ini, config,
"ErrorHandling.WarningFrequency", 1);
}
// If we generated errors while loading RelativeConfigs report those now that
// error reporting is initialized
if (!relConfigsError.empty()) Logger::Error(relConfigsError);
{
if (Config::GetInt64(ini, config, "ResourceLimit.CoreFileSizeOverride")) {
setResourceLimit(RLIMIT_CORE, ini, config,
"ResourceLimit.CoreFileSizeOverride");
} else {
setResourceLimit(RLIMIT_CORE, ini, config, "ResourceLimit.CoreFileSize");
}
setResourceLimit(RLIMIT_NOFILE, ini, config, "ResourceLimit.MaxSocket");
setResourceLimit(RLIMIT_DATA, ini, config, "ResourceLimit.RSS");
// These don't have RuntimeOption::xxx bindings, but we still want to be
// able to use ini_xxx functionality on them; so directly bind to a local
// static via Config::Bind.
static int64_t s_core_file_size_override, s_core_file_size, s_rss = 0;
static int32_t s_max_socket = 0;
Config::Bind(s_core_file_size_override, ini, config,
"ResourceLimit.CoreFileSizeOverride", 0);
Config::Bind(s_core_file_size, ini, config, "ResourceLimit.CoreFileSize",
0);
Config::Bind(s_max_socket, ini, config, "ResourceLimit.MaxSocket", 0);
Config::Bind(s_rss, ini, config, "ResourceLimit.RSS", 0);
Config::Bind(SocketDefaultTimeout, ini, config,
"ResourceLimit.SocketDefaultTimeout", 60);
Config::Bind(MaxSQLRowCount, ini, config, "ResourceLimit.MaxSQLRowCount",
0);
Config::Bind(SerializationSizeLimit, ini, config,
"ResourceLimit.SerializationSizeLimit", StringData::MaxSize);
Config::Bind(HeapSizeMB, ini, config, "ResourceLimit.HeapSizeMB",
HeapSizeMB);
Config::Bind(HeapResetCountBase, ini, config,
"ResourceLimit.HeapResetCountBase", HeapResetCountBase);
Config::Bind(HeapResetCountMultiple, ini, config,
"ResourceLimit.HeapResetCountMultiple",
HeapResetCountMultiple);
Config::Bind(HeapLowWaterMark , ini, config,
"ResourceLimit.HeapLowWaterMark", HeapLowWaterMark);
Config::Bind(HeapHighWaterMark , ini, config,
"ResourceLimit.HeapHighWaterMark",HeapHighWaterMark);
}
{
// watchman
Config::Bind(WatchmanRootSocket, ini, config, "watchman.socket.root", "");
Config::Bind(WatchmanDefaultSocket, ini, config,
"watchman.socket.default", "");
}
{
// PHPisms
Config::Bind(DisableCallUserFunc, ini, config,
"Hack.Lang.Phpism.DisableCallUserFunc",
DisableCallUserFunc);
Config::Bind(DisableCallUserFuncArray, ini, config,
"Hack.Lang.Phpism.DisableCallUserFuncArray",
DisableCallUserFuncArray);
Config::Bind(DisableConstant, ini, config,
"Hack.Lang.Phpism.DisableConstant",
DisableConstant);
}
{
// Repo
auto repoModeToStr = [](RepoMode mode) {
switch (mode) {
case RepoMode::Closed:
return "--";
case RepoMode::ReadOnly:
return "r-";
case RepoMode::ReadWrite:
return "rw";
}
always_assert(false);
return "";
};
auto parseRepoMode = [&](const std::string& repoModeStr, const char* type, RepoMode defaultMode) {
if (repoModeStr.empty()) {
return defaultMode;
}
if (repoModeStr == "--") {
return RepoMode::Closed;
}
if (repoModeStr == "r-") {
return RepoMode::ReadOnly;
}
if (repoModeStr == "rw") {
return RepoMode::ReadWrite;
}
Logger::Error("Bad config setting: Repo.%s.Mode=%s",
type, repoModeStr.c_str());
return RepoMode::ReadWrite;
};
// Local Repo
static std::string repoLocalMode;
Config::Bind(repoLocalMode, ini, config, "Repo.Local.Mode", repoModeToStr(RepoLocalMode));
RepoLocalMode = parseRepoMode(repoLocalMode, "Local", RepoMode::ReadOnly);
// Repo.Path
Config::Bind(RepoPath, ini, config, "Repo.Path", RepoPath);
// Repo.Local.Path
Config::Bind(RepoLocalPath, ini, config, "Repo.Local.Path");
if (RepoLocalPath.empty()) {
const char* HHVM_REPO_LOCAL_PATH = getenv("HHVM_REPO_LOCAL_PATH");
if (HHVM_REPO_LOCAL_PATH != nullptr) {
RepoLocalPath = HHVM_REPO_LOCAL_PATH;
}
}
// Central Repo
static std::string repoCentralMode;
Config::Bind(repoCentralMode, ini, config, "Repo.Central.Mode", repoModeToStr(RepoCentralMode));
RepoCentralMode = parseRepoMode(repoCentralMode, "Central", RepoMode::ReadWrite);
// Repo.Central.Path
Config::Bind(RepoCentralPath, ini, config, "Repo.Central.Path");
Config::Bind(RepoCentralFileMode, ini, config, "Repo.Central.FileMode");
Config::Bind(RepoCentralFileUser, ini, config, "Repo.Central.FileUser");
Config::Bind(RepoCentralFileGroup, ini, config, "Repo.Central.FileGroup");
Config::Bind(RepoAllowFallbackPath, ini, config, "Repo.AllowFallbackPath",
RepoAllowFallbackPath);
replacePlaceholders(RepoLocalPath);
replacePlaceholders(RepoCentralPath);
replacePlaceholders(RepoPath);
Config::Bind(RepoJournal, ini, config, "Repo.Journal", RepoJournal);
Config::Bind(RepoCommit, ini, config, "Repo.Commit",
RepoCommit);
Config::Bind(RepoDebugInfo, ini, config, "Repo.DebugInfo", RepoDebugInfo);
Config::Bind(RepoLitstrLazyLoad, ini, config, "Repo.LitstrLazyLoad",
RepoLitstrLazyLoad);
Config::Bind(RepoAuthoritative, ini, config, "Repo.Authoritative",
RepoAuthoritative);
Config::Bind(RepoLocalReadaheadRate, ini, config,
"Repo.LocalReadaheadRate", 0);
Config::Bind(RepoLocalReadaheadConcurrent, ini, config,
"Repo.LocalReadaheadConcurrent", false);
Config::Bind(RepoBusyTimeoutMS, ini, config,
"Repo.BusyTimeoutMS", RepoBusyTimeoutMS);
if (RepoPath.empty()) {
if (!RepoLocalPath.empty()) {
RepoPath = RepoLocalPath;
} else if (!RepoCentralPath.empty()) {
RepoPath = RepoCentralPath;
} else if (auto const env = getenv("HHVM_REPO_CENTRAL_PATH")) {
RepoPath = env;
replacePlaceholders(RepoPath);
} else {
always_assert_flog(
!RepoAuthoritative,
"Either Repo.Path, Repo.LocalPath, or Repo.CentralPath "
"must be set in RepoAuthoritative mode"
);
}
}
}
if (use_jemalloc) {
// HHProf
Config::Bind(HHProfEnabled, ini, config, "HHProf.Enabled", false);
Config::Bind(HHProfActive, ini, config, "HHProf.Active", false);
Config::Bind(HHProfAccum, ini, config, "HHProf.Accum", false);
Config::Bind(HHProfRequest, ini, config, "HHProf.Request", false);
}
{
// Eval
Config::Bind(EnableHipHopSyntax, ini, config, "Eval.EnableHipHopSyntax",
EnableHipHopSyntax);
Config::Bind(EnableXHP, ini, config, "Eval.EnableXHP", EnableXHP);
Config::Bind(TimeoutsUseWallTime, ini, config, "Eval.TimeoutsUseWallTime",
true);
Config::Bind(CheckFlushOnUserClose, ini, config,
"Eval.CheckFlushOnUserClose", true);
Config::Bind(EvalInitialNamedEntityTableSize, ini, config,
"Eval.InitialNamedEntityTableSize",
EvalInitialNamedEntityTableSize);
Config::Bind(EvalInitialStaticStringTableSize, ini, config,
"Eval.InitialStaticStringTableSize",
EvalInitialStaticStringTableSize);
static std::string jitSerdesMode;
Config::Bind(jitSerdesMode, ini, config, "Eval.JitSerdesMode", "Off");
EvalJitSerdesMode = [&] {
#define X(x) if (jitSerdesMode == #x) return JitSerdesMode::x
X(Serialize);
X(SerializeAndExit);
X(Deserialize);
X(DeserializeOrFail);
X(DeserializeOrGenerate);
X(DeserializeAndDelete);
X(DeserializeAndExit);
#undef X
return JitSerdesMode::Off;
}();
Config::Bind(EvalJitSerdesFile, ini, config,
"Eval.JitSerdesFile", EvalJitSerdesFile);
replacePlaceholders(EvalJitSerdesFile);
// DumpPreciseProfileData defaults to true only when we can possibly write
// profile data to disk. It can be set to false to avoid the performance
// penalty of only running the interpreter during retranslateAll. We will
// assume that DumpPreciseProfileData implies (JitSerdesMode::Serialize ||
// JitSerdesMode::SerializeAndExit), to avoid checking too many flags in a
// few places. The config file should never need to explicitly set
// DumpPreciseProfileData to true.
auto const couldDump = !EvalJitSerdesFile.empty() &&
(isJitSerializing() ||
(EvalJitSerdesMode == JitSerdesMode::DeserializeOrGenerate));
Config::Bind(DumpPreciseProfData, ini, config,
"Eval.DumpPreciseProfData", couldDump);
Config::Bind(ProfDataTTLHours, ini, config,
"Eval.ProfDataTTLHours", ProfDataTTLHours);
Config::Bind(ProfDataTag, ini, config, "Eval.ProfDataTag", ProfDataTag);
Config::Bind(CheckSymLink, ini, config, "Eval.CheckSymLink", true);
Config::Bind(TrustAutoloaderPath, ini, config,
"Eval.TrustAutoloaderPath", false);
#define F(type, name, defaultVal) \
Config::Bind(Eval ## name, ini, config, "Eval."#name, defaultVal);
EVALFLAGS()
#undef F
if (EvalJitSerdesModeForceOff) EvalJitSerdesMode = JitSerdesMode::Off;
if (!EvalEnableReusableTC) EvalReusableTCPadding = 0;
if (numa_num_nodes <= 1) {
EvalEnableNuma = false;
}
Config::Bind(ServerForkEnabled, ini, config,
"Server.Forking.Enabled", ServerForkEnabled);
Config::Bind(ServerForkLogging, ini, config,
"Server.Forking.LogForkAttempts", ServerForkLogging);
if (!ServerForkEnabled && ServerExecutionMode()) {
// Only use hugetlb pages when we don't fork().
low_2m_pages(EvalMaxLowMemHugePages);
high_2m_pages(EvalMaxHighArenaHugePages);
}
#if USE_JEMALLOC_EXTENT_HOOKS
g_useTHPUponHugeTLBFailure =
Config::GetBool(ini, config, "Eval.UseTHPUponHugeTLBFailure",
g_useTHPUponHugeTLBFailure);
#endif
s_enable_static_arena =
Config::GetBool(ini, config, "Eval.UseTLStaticArena", true);
replacePlaceholders(EvalEmbeddedDataExtractPath);
replacePlaceholders(EvalEmbeddedDataFallbackPath);
if (!jit::mcgen::retranslateAllEnabled()) {
EvalJitWorkerThreads = 0;
if (EvalJitSerdesMode != JitSerdesMode::Off) {
if (ServerMode) {
Logger::Warning("Eval.JitSerdesMode reset from " + jitSerdesMode +
" to off, becasue JitRetranslateAll isn't enabled.");
}
EvalJitSerdesMode = JitSerdesMode::Off;
}
EvalJitSerdesFile.clear();
DumpPreciseProfData = false;
}
EvalJitPGOUseAddrCountedCheck &= addr_encodes_persistency;
HardwareCounter::Init(EvalProfileHWEnable,
url_decode(EvalProfileHWEvents.data(),
EvalProfileHWEvents.size()).toCppString(),
false,
EvalProfileHWExcludeKernel,
EvalProfileHWFastReads,
EvalProfileHWExportInterval);
Config::Bind(EnableIntrinsicsExtension, ini,
config, "Eval.EnableIntrinsicsExtension",
EnableIntrinsicsExtension);
Config::Bind(RecordCodeCoverage, ini, config, "Eval.RecordCodeCoverage");
if (EvalJit && RecordCodeCoverage) {
throw std::runtime_error("Code coverage is not supported with "
"Eval.Jit=true");
}
Config::Bind(DisableSmallAllocator, ini, config,
"Eval.DisableSmallAllocator", DisableSmallAllocator);
SetArenaSlabAllocBypass(DisableSmallAllocator);
EvalSlabAllocAlign = folly::nextPowTwo(EvalSlabAllocAlign);
EvalSlabAllocAlign = std::min(EvalSlabAllocAlign,
decltype(EvalSlabAllocAlign){4096});
if (RecordCodeCoverage) CheckSymLink = true;
Config::Bind(CodeCoverageOutputFile, ini, config,
"Eval.CodeCoverageOutputFile");
// NB: after we know the value of RepoAuthoritative.
Config::Bind(EnableArgsInBacktraces, ini, config,
"Eval.EnableArgsInBacktraces", !RepoAuthoritative);
Config::Bind(EvalAuthoritativeMode, ini, config, "Eval.AuthoritativeMode",
false);
Config::Bind(CheckCLIClientCommands, ini, config, "Eval.CheckCLIClientCommands", 1);
if (RepoAuthoritative) {
EvalAuthoritativeMode = true;
}
{
// Debugger (part of Eval)
Config::Bind(EnableHphpdDebugger, ini, config,
"Eval.Debugger.EnableDebugger");
Config::Bind(EnableVSDebugger, ini, config,
"Eval.Debugger.VSDebugEnable", EnableVSDebugger);
Config::Bind(EnableDebuggerColor, ini, config,
"Eval.Debugger.EnableDebuggerColor", true);
Config::Bind(EnableDebuggerPrompt, ini, config,
"Eval.Debugger.EnableDebuggerPrompt", true);
Config::Bind(EnableDebuggerServer, ini, config,
"Eval.Debugger.EnableDebuggerServer");
Config::Bind(EnableDebuggerUsageLog, ini, config,
"Eval.Debugger.EnableDebuggerUsageLog");
Config::Bind(DebuggerServerIP, ini, config, "Eval.Debugger.IP");
Config::Bind(DebuggerServerPort, ini, config, "Eval.Debugger.Port", 8089);
Config::Bind(DebuggerDisableIPv6, ini, config,
"Eval.Debugger.DisableIPv6", false);
Config::Bind(DebuggerDefaultSandboxPath, ini, config,
"Eval.Debugger.DefaultSandboxPath");
Config::Bind(DebuggerStartupDocument, ini, config,
"Eval.Debugger.StartupDocument");
Config::Bind(DebuggerSignalTimeout, ini, config,
"Eval.Debugger.SignalTimeout", 1);
Config::Bind(DebuggerAuthTokenScriptBin, ini, config,
"Eval.Debugger.Auth.TokenScriptBin");
Config::Bind(DebuggerSessionAuthScriptBin, ini, config,
"Eval.Debugger.Auth.SessionAuthScriptBin");
}
}
{
// CodeCache
using jit::CodeCache;
Config::Bind(CodeCache::ASize, ini, config, "Eval.JitASize", 60 << 20);
Config::Bind(CodeCache::AColdSize, ini, config, "Eval.JitAColdSize",
24 << 20);
Config::Bind(CodeCache::AFrozenSize, ini, config, "Eval.JitAFrozenSize",
40 << 20);
Config::Bind(CodeCache::ABytecodeSize, ini, config,
"Eval.JitABytecodeSize", 0);
Config::Bind(CodeCache::GlobalDataSize, ini, config,
"Eval.JitGlobalDataSize", CodeCache::ASize >> 2);
Config::Bind(CodeCache::MapTCHuge, ini, config, "Eval.MapTCHuge",
hugePagesSoundNice());
Config::Bind(CodeCache::TCNumHugeHotMB, ini, config,
"Eval.TCNumHugeHotMB", 64);
Config::Bind(CodeCache::TCNumHugeMainMB, ini, config,
"Eval.TCNumHugeMainMB", 16);
Config::Bind(CodeCache::TCNumHugeColdMB, ini, config,
"Eval.TCNumHugeColdMB", 4);
Config::Bind(CodeCache::AutoTCShift, ini, config, "Eval.JitAutoTCShift", 1);
}
{
// Hack Language
Config::Bind(CheckIntOverflow, ini, config,
"Hack.Lang.CheckIntOverflow", 0);
Config::Bind(StrictArrayFillKeys, ini, config,
"Hack.Lang.StrictArrayFillKeys", HackStrictOption::ON);
Config::Bind(LookForTypechecker, ini, config,
"Hack.Lang.LookForTypechecker", false);
// If you turn off LookForTypechecker, you probably want to turn this off
// too -- basically, make the two look like the same option to external
// users, unless you really explicitly want to set them differently for
// some reason.
Config::Bind(AutoTypecheck, ini, config, "Hack.Lang.AutoTypecheck",
LookForTypechecker);
Config::Bind(EnableClassLevelWhereClauses, ini, config,
"Hack.Lang.EnableClassLevelWhereClauses",
false);
}
{
// Options for PHP7 features which break BC. (Features which do not break
// BC don't need options here and can just always be turned on.)
//
// NB that the "PHP7.all" option is intended to be only a master switch;
// all runtime behavior gating should be based on sub-options (that's why
// it's a file static not a static member of RuntimeOption). Also don't
// forget to update mangleUnitPHP7Options if needed.
//
// TODO: we may eventually want to make an option which specifies
// directories or filenames to exclude from PHP7 behavior, and so checking
// these may want to be per-file. We originally planned to do this from the
// get-go, but threading that through turns out to be kind of annoying and
// of questionable value, so just doing this for now.
Config::Bind(s_PHP7_master, ini, config, "PHP7.all", s_PHP7_default);
Config::Bind(PHP7_EngineExceptions, ini, config, "PHP7.EngineExceptions",
s_PHP7_master);
Config::Bind(PHP7_NoHexNumerics, ini, config, "PHP7.NoHexNumerics",
s_PHP7_master);
Config::Bind(PHP7_Builtins, ini, config, "PHP7.Builtins", s_PHP7_master);
Config::Bind(PHP7_Substr, ini, config, "PHP7.Substr",
s_PHP7_master);
Config::Bind(PHP7_DisallowUnsafeCurlUploads, ini, config,
"PHP7.DisallowUnsafeCurlUploads", s_PHP7_master);
}
{
// Server
Config::Bind(Host, ini, config, "Server.Host");
Config::Bind(DefaultServerNameSuffix, ini, config,
"Server.DefaultServerNameSuffix");
Config::Bind(AlwaysDecodePostDataDefault, ini, config,
"Server.AlwaysDecodePostDataDefault",
AlwaysDecodePostDataDefault);
Config::Bind(ServerType, ini, config, "Server.Type", ServerType);
Config::Bind(ServerIP, ini, config, "Server.IP");
Config::Bind(ServerFileSocket, ini, config, "Server.FileSocket");
#ifdef FACEBOOK
//Do not cause slowness on startup -- except for Facebook
if (GetServerPrimaryIPv4().empty() && GetServerPrimaryIPv6().empty()) {
throw std::runtime_error("Unable to resolve the server's "
"IPv4 or IPv6 address");
}
#endif
Config::Bind(ServerPort, ini, config, "Server.Port", 80);
Config::Bind(ServerBacklog, ini, config, "Server.Backlog", 128);
Config::Bind(ServerConnectionLimit, ini, config,
"Server.ConnectionLimit", 0);
Config::Bind(ServerThreadCount, ini, config, "Server.ThreadCount",
Process::GetCPUCount() * 2);
Config::Bind(ServerQueueCount, ini, config, "Server.QueueCount",
ServerThreadCount);
Config::Bind(ServerIOThreadCount, ini, config,
"Server.IOThreadCount", 1);
Config::Bind(ServerLegacyBehavior, ini, config, "Server.LegacyBehavior",
ServerLegacyBehavior);
Config::Bind(ServerHugeThreadCount, ini, config,
"Server.HugeThreadCount", 0);
Config::Bind(ServerHugeStackKb, ini, config, "Server.HugeStackSizeKb", 384);
ServerSchedPolicy =
Config::GetInt32(ini, config, "Server.SchedPolicy", ServerSchedPolicy);
ServerSchedPriority =
Config::GetInt32(ini, config, "Server.SchedPriority", ServerSchedPriority);
Config::Bind(ServerLoopSampleRate, ini, config,
"Server.LoopSampleRate", 0);
Config::Bind(ServerWarmupThrottleRequestCount, ini, config,
"Server.WarmupThrottleRequestCount",
ServerWarmupThrottleRequestCount);
Config::Bind(ServerWarmupThrottleThreadCount, ini, config,
"Server.WarmupThrottleThreadCount",
Process::GetCPUCount());
Config::Bind(ServerThreadDropCacheTimeoutSeconds, ini, config,
"Server.ThreadDropCacheTimeoutSeconds", 0);
if (Config::GetBool(ini, config, "Server.ThreadJobLIFO")) {
ServerThreadJobLIFOSwitchThreshold = 0;
}
Config::Bind(ServerThreadJobLIFOSwitchThreshold, ini, config,
"Server.ThreadJobLIFOSwitchThreshold",
ServerThreadJobLIFOSwitchThreshold);
Config::Bind(ServerThreadJobMaxQueuingMilliSeconds, ini, config,
"Server.ThreadJobMaxQueuingMilliSeconds", -1);
Config::Bind(ServerThreadDropStack, ini, config, "Server.ThreadDropStack");
Config::Bind(ServerHttpSafeMode, ini, config, "Server.HttpSafeMode");
Config::Bind(ServerStatCache, ini, config, "Server.StatCache", false);
Config::Bind(ServerFixPathInfo, ini, config, "Server.FixPathInfo", false);
Config::Bind(ServerAddVaryEncoding, ini, config, "Server.AddVaryEncoding",
ServerAddVaryEncoding);
Config::Bind(ServerLogSettingsOnStartup, ini, config,
"Server.LogSettingsOnStartup", false);
Config::Bind(ServerLogReorderProps, ini, config,
"Server.LogReorderProps", false);
Config::Bind(ServerWarmupConcurrently, ini, config,
"Server.WarmupConcurrently", false);
Config::Bind(ServerDedupeWarmupRequests, ini, config,
"Server.DedupeWarmupRequests", false);
Config::Bind(ServerWarmupThreadCount, ini, config,
"Server.WarmupThreadCount", ServerWarmupThreadCount);
Config::Bind(ServerExtendedWarmupThreadCount, ini, config,
"Server.ExtendedWarmup.ThreadCount",
ServerExtendedWarmupThreadCount);
Config::Bind(ServerExtendedWarmupDelaySeconds, ini, config,
"Server.ExtendedWarmup.DelaySeconds",
ServerExtendedWarmupDelaySeconds);
Config::Bind(ServerExtendedWarmupRepeat, ini, config,
"Server.ExtendedWarmup.Repeat", ServerExtendedWarmupRepeat);
Config::Bind(ServerWarmupRequests, ini, config, "Server.WarmupRequests");
Config::Bind(ServerExtendedWarmupRequests, ini, config,
"Server.ExtendedWarmup.Requests");
Config::Bind(ServerCleanupRequest, ini, config, "Server.CleanupRequest");
Config::Bind(ServerInternalWarmupThreads, ini, config,
"Server.InternalWarmupThreads", 0); // 0 = skip
Config::Bind(ServerHighPriorityEndPoints, ini, config,
"Server.HighPriorityEndPoints");
Config::Bind(ServerExitOnBindFail, ini, config, "Server.ExitOnBindFail",
false);
Config::Bind(RequestTimeoutSeconds, ini, config,
"Server.RequestTimeoutSeconds", 0);
Config::Bind(MaxRequestAgeFactor, ini, config, "Server.MaxRequestAgeFactor",
0);
Config::Bind(PspTimeoutSeconds, ini, config, "Server.PspTimeoutSeconds", 0);
Config::Bind(PspCpuTimeoutSeconds, ini, config,
"Server.PspCpuTimeoutSeconds", 0);
Config::Bind(RequestMemoryMaxBytes, ini, config,
"Server.RequestMemoryMaxBytes", (16LL << 30)); // 16GiB
RequestInfo::setOOMKillThreshold(
Config::GetUInt64(ini, config, "Server.RequestMemoryOOMKillBytes",
128ULL << 20));
Config::Bind(RequestHugeMaxBytes, ini, config,
"Server.RequestHugeMaxBytes", (24LL << 20));
Config::Bind(ServerGracefulShutdownWait, ini,
config, "Server.GracefulShutdownWait", 0);
Config::Bind(ServerHarshShutdown, ini, config, "Server.HarshShutdown",
true);
Config::Bind(ServerKillOnTimeout, ini, config, "Server.KillOnTimeout",
true);
Config::Bind(ServerEvilShutdown, ini, config, "Server.EvilShutdown", true);
Config::Bind(ServerPreShutdownWait, ini, config,
"Server.PreShutdownWait", 0);
Config::Bind(ServerShutdownListenWait, ini, config,
"Server.ShutdownListenWait", 0);
Config::Bind(ServerShutdownEOMWait, ini, config,
"Server.ShutdownEOMWait", 0);
Config::Bind(ServerPrepareToStopTimeout, ini, config,
"Server.PrepareToStopTimeout", 240);
Config::Bind(ServerPartialPostStatusCode, ini, config,
"Server.PartialPostStatusCode", -1);
Config::Bind(StopOldServer, ini, config, "Server.StopOld", false);
Config::Bind(OldServerWait, ini, config, "Server.StopOldWait", 30);
Config::Bind(ServerRSSNeededMb, ini, config, "Server.RSSNeededMb", 4096);
Config::Bind(ServerCriticalFreeMb, ini, config,
"Server.CriticalFreeMb", 512);
Config::Bind(CacheFreeFactor, ini, config, "Server.CacheFreeFactor", 50);
if (CacheFreeFactor > 100) CacheFreeFactor = 100;
if (CacheFreeFactor < 0) CacheFreeFactor = 0;
Config::Bind(ServerNextProtocols, ini, config, "Server.SSLNextProtocols");
Config::Bind(ServerEnableH2C, ini, config, "Server.EnableH2C");
extern bool g_brotliUseLocalArena;
Config::Bind(g_brotliUseLocalArena, ini, config,
"Server.BrotliUseLocalArena", g_brotliUseLocalArena);
Config::Bind(BrotliCompressionEnabled, ini, config,
"Server.BrotliCompressionEnabled", -1);
Config::Bind(BrotliChunkedCompressionEnabled, ini, config,
"Server.BrotliChunkedCompressionEnabled", -1);
Config::Bind(BrotliCompressionLgWindowSize, ini, config,
"Server.BrotliCompressionLgWindowSize", 20);
Config::Bind(BrotliCompressionMode, ini, config,
"Server.BrotliCompressionMode", 0);
Config::Bind(BrotliCompressionQuality, ini, config,
"Server.BrotliCompressionQuality", 6);
Config::Bind(ZstdCompressionEnabled, ini, config,
"Server.ZstdCompressionEnabled", -1);
Config::Bind(ZstdCompressor::s_useLocalArena, ini, config,
"Server.ZstdUseLocalArena", ZstdCompressor::s_useLocalArena);
Config::Bind(ZstdCompressionLevel, ini, config,
"Server.ZstdCompressionLevel", 3);
Config::Bind(ZstdChecksumRate, ini, config,
"Server.ZstdChecksumRate", 0);
Config::Bind(GzipCompressionLevel, ini, config,
"Server.GzipCompressionLevel", 3);
Config::Bind(GzipMaxCompressionLevel, ini, config,
"Server.GzipMaxCompressionLevel", 9);
Config::Bind(GzipCompressor::s_useLocalArena, ini, config,
"Server.GzipUseLocalArena", GzipCompressor::s_useLocalArena);
Config::Bind(EnableKeepAlive, ini, config, "Server.EnableKeepAlive", true);
Config::Bind(ExposeHPHP, ini, config, "Server.ExposeHPHP", true);
Config::Bind(ExposeXFBServer, ini, config, "Server.ExposeXFBServer", false);
Config::Bind(ExposeXFBDebug, ini, config, "Server.ExposeXFBDebug", false);
Config::Bind(XFBDebugSSLKey, ini, config, "Server.XFBDebugSSLKey", "");
Config::Bind(ConnectionTimeoutSeconds, ini, config,
"Server.ConnectionTimeoutSeconds", -1);
Config::Bind(EnableOutputBuffering, ini, config,
"Server.EnableOutputBuffering");
Config::Bind(OutputHandler, ini, config, "Server.OutputHandler");
Config::Bind(ImplicitFlush, ini, config, "Server.ImplicitFlush");
Config::Bind(EnableEarlyFlush, ini, config, "Server.EnableEarlyFlush",
true);
Config::Bind(ForceChunkedEncoding, ini, config,
"Server.ForceChunkedEncoding");
Config::Bind(MaxPostSize, ini, config, "Server.MaxPostSize", 100);
MaxPostSize <<= 20;
Config::Bind(AlwaysPopulateRawPostData, ini, config,
"Server.AlwaysPopulateRawPostData", false);
Config::Bind(TakeoverFilename, ini, config, "Server.TakeoverFilename");
Config::Bind(ExpiresActive, ini, config, "Server.ExpiresActive", true);
Config::Bind(ExpiresDefault, ini, config, "Server.ExpiresDefault", 2592000);
if (ExpiresDefault < 0) ExpiresDefault = 2592000;
Config::Bind(DefaultCharsetName, ini, config, "Server.DefaultCharsetName",
"");
Config::Bind(RequestBodyReadLimit, ini, config,
"Server.RequestBodyReadLimit", -1);
Config::Bind(EnableSSL, ini, config, "Server.EnableSSL");
Config::Bind(SSLPort, ini, config, "Server.SSLPort", 443);
Config::Bind(SSLCertificateFile, ini, config, "Server.SSLCertificateFile");
Config::Bind(SSLCertificateKeyFile, ini, config,
"Server.SSLCertificateKeyFile");
Config::Bind(SSLCertificateDir, ini, config, "Server.SSLCertificateDir");
Config::Bind(SSLTicketSeedFile, ini, config, "Server.SSLTicketSeedFile");
Config::Bind(TLSDisableTLS1_2, ini, config, "Server.TLSDisableTLS1_2",
false);
Config::Bind(TLSClientCipherSpec, ini, config,
"Server.TLSClientCipherSpec");
Config::Bind(EnableSSLWithPlainText, ini, config,
"Server.EnableSSLWithPlainText");
Config::Bind(SSLClientAuthLevel, ini, config,
"Server.SSLClientAuthLevel", 0);
if (SSLClientAuthLevel < 0) SSLClientAuthLevel = 0;
if (SSLClientAuthLevel > 2) SSLClientAuthLevel = 2;
Config::Bind(SSLClientCAFile, ini, config, "Server.SSLClientCAFile", "");
if (!SSLClientAuthLevel) {
SSLClientCAFile = "";
} else if (SSLClientCAFile.empty()) {
throw std::runtime_error(
"SSLClientCAFile is required to enable client auth");
}
Config::Bind(ClientAuthAclIdentity, ini, config,
"Server.ClientAuthAclIdentity", "");
Config::Bind(ClientAuthAclAction, ini, config,
"Server.ClientAuthAclAction", "");
Config::Bind(ClientAuthFailClose, ini, config,
"Server.ClientAuthFailClose", false);
Config::Bind(ClientAuthLogSampleBase, ini, config,
"Server.ClientAuthLogSampleBase", 100);
if (ClientAuthLogSampleBase < 1) {
ClientAuthLogSampleBase = 1;
}
Config::Bind(SSLClientAuthLoggingSampleRatio, ini, config,
"Server.SSLClientAuthLoggingSampleRatio", 0);
if (SSLClientAuthLoggingSampleRatio < 0) {
SSLClientAuthLoggingSampleRatio = 0;
}
if (SSLClientAuthLoggingSampleRatio > ClientAuthLogSampleBase) {
SSLClientAuthLoggingSampleRatio = ClientAuthLogSampleBase;
}
Config::Bind(ClientAuthSuccessLogSampleRatio, ini, config,
"Server.ClientAuthSuccessLogSampleRatio", 0);
if (ClientAuthSuccessLogSampleRatio <
SSLClientAuthLoggingSampleRatio) {
ClientAuthSuccessLogSampleRatio = SSLClientAuthLoggingSampleRatio;
}
if (ClientAuthSuccessLogSampleRatio > ClientAuthLogSampleBase) {
ClientAuthSuccessLogSampleRatio = ClientAuthLogSampleBase;
}
Config::Bind(ClientAuthFailureLogSampleRatio, ini, config,
"Server.ClientAuthFailureLogSampleRatio", 0);
if (ClientAuthFailureLogSampleRatio <
SSLClientAuthLoggingSampleRatio) {
ClientAuthFailureLogSampleRatio = SSLClientAuthLoggingSampleRatio;
}
if (ClientAuthFailureLogSampleRatio > ClientAuthLogSampleBase) {
ClientAuthFailureLogSampleRatio = ClientAuthLogSampleBase;
}
// SourceRoot has been default to: Process::GetCurrentDirectory() + '/'
auto defSourceRoot = SourceRoot;
Config::Bind(SourceRoot, ini, config, "Server.SourceRoot", SourceRoot);
SourceRoot = FileUtil::normalizeDir(SourceRoot);
if (SourceRoot.empty()) {
SourceRoot = defSourceRoot;
}
FileCache::SourceRoot = SourceRoot;
Config::Bind(IncludeSearchPaths, ini, config, "Server.IncludeSearchPaths");
for (unsigned int i = 0; i < IncludeSearchPaths.size(); i++) {
IncludeSearchPaths[i] = FileUtil::normalizeDir(IncludeSearchPaths[i]);
}
IncludeSearchPaths.insert(IncludeSearchPaths.begin(), ".");
Config::Bind(AutoloadEnabled, ini, config, "Autoload.Enabled", false);
Config::Bind(AutoloadDBPath, ini, config, "Autoload.DB.Path");
Config::Bind(AutoloadDBPerms, ini, config, "Autoload.DB.Perms", "0644");
Config::Bind(AutoloadDBGroup, ini, config, "Autoload.DB.Group");
Config::Bind(AutoloadLogging, ini, config, "Autoload.Logging",
"hphp.runtime.ext.facts:=CRITICAL:slog;slog=hhvm");
Config::Bind(AutoloadExcludedRepos, ini, config, "Autoload.ExcludedRepos");
Config::Bind(AutoloadLoggingAllowPropagation, ini, config,
"Autoload.AllowLoggingPropagation", false);
Config::Bind(AutoloadRethrowExceptions, ini, config,
"Autoload.RethrowExceptions", true);
Config::Bind(FileCache, ini, config, "Server.FileCache");
Config::Bind(DefaultDocument, ini, config, "Server.DefaultDocument",
"index.php");
Config::Bind(GlobalDocument, ini, config, "Server.GlobalDocument");
Config::Bind(ErrorDocument404, ini, config, "Server.ErrorDocument404");
normalizePath(ErrorDocument404);
Config::Bind(ForbiddenAs404, ini, config, "Server.ForbiddenAs404");
Config::Bind(ErrorDocument500, ini, config, "Server.ErrorDocument500");
normalizePath(ErrorDocument500);
Config::Bind(FatalErrorMessage, ini, config, "Server.FatalErrorMessage");
FontPath = FileUtil::normalizeDir(
Config::GetString(ini, config, "Server.FontPath"));
Config::Bind(EnableStaticContentFromDisk, ini, config,
"Server.EnableStaticContentFromDisk", true);
Config::Bind(EnableOnDemandUncompress, ini, config,
"Server.EnableOnDemandUncompress", true);
Config::Bind(EnableStaticContentMMap, ini, config,
"Server.EnableStaticContentMMap", true);
if (EnableStaticContentMMap) {
EnableOnDemandUncompress = true;
}
Config::Bind(Utf8izeReplace, ini, config, "Server.Utf8izeReplace", true);
Config::Bind(RequestInitFunction, ini, config,
"Server.RequestInitFunction");
Config::Bind(RequestInitDocument, ini, config,
"Server.RequestInitDocument");
Config::Bind(SafeFileAccess, ini, config, "Server.SafeFileAccess");
Config::Bind(AllowedDirectories, ini, config, "Server.AllowedDirectories");
Config::Bind(WhitelistExec, ini, config, "Server.WhitelistExec");
Config::Bind(WhitelistExecWarningOnly, ini, config,
"Server.WhitelistExecWarningOnly");
Config::Bind(AllowedExecCmds, ini, config, "Server.AllowedExecCmds");
Config::Bind(UnserializationWhitelistCheck, ini, config,
"Server.UnserializationWhitelistCheck", false);
Config::Bind(UnserializationWhitelistCheckWarningOnly, ini, config,
"Server.UnserializationWhitelistCheckWarningOnly", true);
Config::Bind(UnserializationBigMapThreshold, ini, config,
"Server.UnserializationBigMapThreshold", 1 << 16);
Config::Bind(AllowedFiles, ini, config, "Server.AllowedFiles");
Config::Bind(ForbiddenFileExtensions, ini, config,
"Server.ForbiddenFileExtensions");
Config::Bind(LockCodeMemory, ini, config, "Server.LockCodeMemory", false);
Config::Bind(MaxArrayChain, ini, config, "Server.MaxArrayChain", INT_MAX);
if (MaxArrayChain != INT_MAX) {
// VanillaDict needs a higher threshold to avoid false-positives.
// (and we always use VanillaDict)
MaxArrayChain *= 2;
}
Config::Bind(WarnOnCollectionToArray, ini, config,
"Server.WarnOnCollectionToArray", false);
Config::Bind(UseDirectCopy, ini, config, "Server.UseDirectCopy", false);
Config::Bind(AlwaysUseRelativePath, ini, config,
"Server.AlwaysUseRelativePath", false);
{
// Server Upload
Config::Bind(UploadMaxFileSize, ini, config,
"Server.Upload.UploadMaxFileSize", 100);
UploadMaxFileSize <<= 20;
Config::Bind(UploadTmpDir, ini, config, "Server.Upload.UploadTmpDir",
"/tmp");
Config::Bind(EnableFileUploads, ini, config,
"Server.Upload.EnableFileUploads", true);
Config::Bind(MaxFileUploads, ini, config, "Server.Upload.MaxFileUploads",
20);
Config::Bind(EnableUploadProgress, ini, config,
"Server.Upload.EnableUploadProgress");
Config::Bind(Rfc1867Freq, ini, config, "Server.Upload.Rfc1867Freq",
256 * 1024);
if (Rfc1867Freq < 0) Rfc1867Freq = 256 * 1024;
Config::Bind(Rfc1867Prefix, ini, config, "Server.Upload.Rfc1867Prefix",
"vupload_");
Config::Bind(Rfc1867Name, ini, config, "Server.Upload.Rfc1867Name",
"video_ptoken");
}
Config::Bind(ImageMemoryMaxBytes, ini, config,
"Server.ImageMemoryMaxBytes", 0);
if (ImageMemoryMaxBytes == 0) {
ImageMemoryMaxBytes = UploadMaxFileSize * 2;
}
Config::Bind(LightProcessFilePrefix, ini, config,
"Server.LightProcessFilePrefix", "./lightprocess");
Config::Bind(LightProcessCount, ini, config,
"Server.LightProcessCount", 0);
Config::Bind(LightProcess::g_strictUser, ini, config,
"Server.LightProcessStrictUser", false);
Config::Bind(ForceServerNameToHeader, ini, config,
"Server.ForceServerNameToHeader");
Config::Bind(PathDebug, ini, config, "Server.PathDebug", false);
Config::Bind(ServerUser, ini, config, "Server.User", "");
Config::Bind(AllowRunAsRoot, ini, config, "Server.AllowRunAsRoot", false);
}
VirtualHost::SortAllowedDirectories(AllowedDirectories);
{
auto vh_callback = [] (const IniSettingMap &ini_vh, const Hdf &hdf_vh,
const std::string &ini_vh_key) {
if (VirtualHost::IsDefault(ini_vh, hdf_vh, ini_vh_key)) {
VirtualHost::GetDefault().init(ini_vh, hdf_vh, ini_vh_key);
VirtualHost::GetDefault().addAllowedDirectories(AllowedDirectories);
} else {
auto host = std::make_shared<VirtualHost>(ini_vh, hdf_vh, ini_vh_key);
host->addAllowedDirectories(AllowedDirectories);
VirtualHosts.push_back(host);
}
};
// Virtual Hosts have to be iterated in order. Because only the first
// one that matches in the VirtualHosts vector gets applied and used.
// Hdf's and ini (via Variant arrays) internal storage handles ordering
// naturally (as specified top to bottom in the file and left to right on
// the command line.
Config::Iterate(vh_callback, ini, config, "VirtualHost");
LowestMaxPostSize = VirtualHost::GetLowestMaxPostSize();
}
{
// IpBlocks
IpBlocks = std::make_shared<IpBlockMap>(ini, config);
}
{
ReadSatelliteInfo(ini, config, SatelliteServerInfos,
XboxPassword, XboxPasswords);
}
{
// Xbox
Config::Bind(XboxServerThreadCount, ini, config,
"Xbox.ServerInfo.ThreadCount", 10);
Config::Bind(XboxServerMaxQueueLength, ini, config,
"Xbox.ServerInfo.MaxQueueLength", INT_MAX);
if (XboxServerMaxQueueLength < 0) XboxServerMaxQueueLength = INT_MAX;
Config::Bind(XboxServerInfoMaxRequest, ini, config,
"Xbox.ServerInfo.MaxRequest", 500);
Config::Bind(XboxServerInfoDuration, ini, config,
"Xbox.ServerInfo.MaxDuration", 120);
Config::Bind(XboxServerInfoReqInitFunc, ini, config,
"Xbox.ServerInfo.RequestInitFunction", "");
Config::Bind(XboxServerInfoReqInitDoc, ini, config,
"Xbox.ServerInfo.RequestInitDocument", "");
Config::Bind(XboxServerInfoAlwaysReset, ini, config,
"Xbox.ServerInfo.AlwaysReset", false);
Config::Bind(XboxServerLogInfo, ini, config, "Xbox.ServerInfo.LogInfo",
false);
Config::Bind(XboxProcessMessageFunc, ini, config, "Xbox.ProcessMessageFunc",
"xbox_process_message");
}
{
// Pagelet Server
Config::Bind(PageletServerThreadCount, ini, config,
"PageletServer.ThreadCount", 0);
Config::Bind(PageletServerHugeThreadCount, ini, config,
"PageletServer.HugeThreadCount", 0);
Config::Bind(PageletServerThreadDropStack, ini, config,
"PageletServer.ThreadDropStack");
Config::Bind(PageletServerThreadDropCacheTimeoutSeconds, ini, config,
"PageletServer.ThreadDropCacheTimeoutSeconds", 0);
Config::Bind(PageletServerQueueLimit, ini, config,
"PageletServer.QueueLimit", 0);
}
{
// Static File
hphp_string_imap<std::string> staticFileDefault;
staticFileDefault["css"] = "text/css";
staticFileDefault["gif"] = "image/gif";
staticFileDefault["html"] = "text/html";
staticFileDefault["jpeg"] = "image/jpeg";
staticFileDefault["jpg"] = "image/jpeg";
staticFileDefault["mp3"] = "audio/mpeg";
staticFileDefault["png"] = "image/png";
staticFileDefault["tif"] = "image/tiff";
staticFileDefault["tiff"] = "image/tiff";
staticFileDefault["txt"] = "text/plain";
staticFileDefault["zip"] = "application/zip";
Config::Bind(StaticFileExtensions, ini, config, "StaticFile.Extensions",
staticFileDefault);
auto matches_callback = [](const IniSettingMap& ini_m, const Hdf& hdf_m,
const std::string& /*ini_m_key*/) {
FilesMatches.push_back(std::make_shared<FilesMatch>(ini_m, hdf_m));
};
Config::Iterate(matches_callback, ini, config, "StaticFile.FilesMatch");
}
{
// PhpFile
Config::Bind(PhpFileExtensions, ini, config, "PhpFile.Extensions");
}
{
// Admin Server
Config::Bind(AdminServerIP, ini, config, "AdminServer.IP", ServerIP);
Config::Bind(AdminServerPort, ini, config, "AdminServer.Port", 0);
Config::Bind(AdminThreadCount, ini, config, "AdminServer.ThreadCount", 1);
Config::Bind(AdminServerEnableSSLWithPlainText, ini, config,
"AdminServer.EnableSSLWithPlainText", false);
Config::Bind(AdminServerStatsNeedPassword, ini, config,
"AdminServer.StatsNeedPassword", AdminServerStatsNeedPassword);
AdminPassword = Config::GetString(ini, config, "AdminServer.Password");
AdminPasswords = Config::GetSet(ini, config, "AdminServer.Passwords");
HashedAdminPasswords =
Config::GetSet(ini, config, "AdminServer.HashedPasswords");
Config::Bind(AdminDumpPath, ini, config,
"AdminServer.DumpPath", "/tmp/hhvm_admin_dump");
}
{
// Proxy
Config::Bind(ProxyOriginRaw, ini, config, "Proxy.Origin");
Config::Bind(ProxyPercentageRaw, ini, config, "Proxy.Percentage", 0);
Config::Bind(ProxyRetry, ini, config, "Proxy.Retry", 3);
Config::Bind(UseServeURLs, ini, config, "Proxy.ServeURLs");
Config::Bind(ServeURLs, ini, config, "Proxy.ServeURLs");
Config::Bind(UseProxyURLs, ini, config, "Proxy.ProxyURLs");
Config::Bind(ProxyURLs, ini, config, "Proxy.ProxyURLs");
Config::Bind(ProxyPatterns, ini, config, "Proxy.ProxyPatterns");
}
{
// Http
Config::Bind(HttpDefaultTimeout, ini, config, "Http.DefaultTimeout", 30);
Config::Bind(HttpSlowQueryThreshold, ini, config, "Http.SlowQueryThreshold",
5000);
}
{
// Debug
Config::Bind(NativeStackTrace, ini, config, "Debug.NativeStackTrace");
StackTrace::Enabled = NativeStackTrace;
Config::Bind(ServerErrorMessage, ini, config, "Debug.ServerErrorMessage");
Config::Bind(RecordInput, ini, config, "Debug.RecordInput");
Config::Bind(ClearInputOnSuccess, ini, config, "Debug.ClearInputOnSuccess",
true);
Config::Bind(ProfilerOutputDir, ini, config, "Debug.ProfilerOutputDir",
"/tmp");
Config::Bind(CoreDumpEmail, ini, config, "Debug.CoreDumpEmail");
Config::Bind(CoreDumpReport, ini, config, "Debug.CoreDumpReport", true);
if (CoreDumpReport) {
install_crash_reporter();
}
// Binding default dependenant on whether we are using an OSS build or
// not, and that is set at initialization time of CoreDumpReportDirectory.
Config::Bind(CoreDumpReportDirectory, ini, config,
"Debug.CoreDumpReportDirectory", CoreDumpReportDirectory);
std::ostringstream stack_trace_stream;
stack_trace_stream << CoreDumpReportDirectory << "/stacktrace."
<< (int64_t)getpid() << ".log";
StackTraceFilename = stack_trace_stream.str();
Config::Bind(StackTraceTimeout, ini, config, "Debug.StackTraceTimeout", 0);
Config::Bind(RemoteTraceOutputDir, ini, config,
"Debug.RemoteTraceOutputDir", "/tmp");
Config::Bind(TraceFunctions, ini, config,
"Debug.TraceFunctions", TraceFunctions);
}
{
// Stats
Config::Bind(EnableStats, ini, config, "Stats.Enable",
false); // main switch
Config::Bind(EnableAPCStats, ini, config, "Stats.APC", false);
Config::Bind(EnableWebStats, ini, config, "Stats.Web");
Config::Bind(EnableMemoryStats, ini, config, "Stats.Memory");
Config::Bind(EnableSQLStats, ini, config, "Stats.SQL");
Config::Bind(EnableSQLTableStats, ini, config, "Stats.SQLTable");
Config::Bind(EnableNetworkIOStatus, ini, config, "Stats.NetworkIO");
Config::Bind(StatsXSL, ini, config, "Stats.XSL");
Config::Bind(StatsXSLProxy, ini, config, "Stats.XSLProxy");
Config::Bind(StatsSlotDuration, ini, config, "Stats.SlotDuration", 10 * 60);
Config::Bind(StatsMaxSlot, ini, config, "Stats.MaxSlot",
12 * 6); // 12 hours
StatsSlotDuration = std::max(1u, StatsSlotDuration);
StatsMaxSlot = std::max(2u, StatsMaxSlot);
Config::Bind(EnableHotProfiler, ini, config, "Stats.EnableHotProfiler",
true);
Config::Bind(ProfilerTraceBuffer, ini, config, "Stats.ProfilerTraceBuffer",
2000000);
Config::Bind(ProfilerTraceExpansion, ini, config,
"Stats.ProfilerTraceExpansion", 1.2);
Config::Bind(ProfilerMaxTraceBuffer, ini, config,
"Stats.ProfilerMaxTraceBuffer", 0);
Config::Bind(TrackPerUnitMemory, ini, config,
"Stats.TrackPerUnitMemory", false);
}
{
Config::Bind(ServerVariables, ini, config, "ServerVariables");
Config::Bind(EnvVariables, ini, config, "EnvVariables");
}
{
// Sandbox
Config::Bind(SandboxMode, ini, config, "Sandbox.SandboxMode");
Config::Bind(SandboxPattern, ini, config, "Sandbox.Pattern");
SandboxPattern = format_pattern(SandboxPattern, true);
Config::Bind(SandboxHome, ini, config, "Sandbox.Home");
Config::Bind(SandboxFallback, ini, config, "Sandbox.Fallback");
Config::Bind(SandboxConfFile, ini, config, "Sandbox.ConfFile");
Config::Bind(SandboxFromCommonRoot, ini, config, "Sandbox.FromCommonRoot");
Config::Bind(SandboxDirectoriesRoot, ini, config,
"Sandbox.DirectoriesRoot");
Config::Bind(SandboxLogsRoot, ini, config, "Sandbox.LogsRoot");
Config::Bind(SandboxServerVariables, ini, config,
"Sandbox.ServerVariables");
Config::Bind(SandboxDefaultUserFile, ini, config,
"Sandbox.DefaultUserFile");
Config::Bind(SandboxHostAlias, ini, config, "Sandbox.HostAlias");
}
{
// Mail
Config::Bind(SendmailPath, ini, config, "Mail.SendmailPath",
"/usr/lib/sendmail -t -i");
Config::Bind(MailForceExtraParameters, ini, config,
"Mail.ForceExtraParameters");
}
{
// Preg
Config::Bind(PregBacktraceLimit, ini, config, "Preg.BacktraceLimit",
1000000);
Config::Bind(PregRecursionLimit, ini, config, "Preg.RecursionLimit",
100000);
Config::Bind(EnablePregErrorLog, ini, config, "Preg.ErrorLog", true);
}
{
// SimpleXML
Config::Bind(SimpleXMLEmptyNamespaceMatchesAll, ini, config,
"SimpleXML.EmptyNamespaceMatchesAll", false);
}
#ifdef FACEBOOK
{
// Fb303Server
Config::Bind(EnableFb303Server, ini, config, "Fb303Server.Enable",
EnableFb303Server);
Config::Bind(Fb303ServerPort, ini, config, "Fb303Server.Port", 0);
Config::Bind(Fb303ServerIP, ini, config, "Fb303Server.IP");
Config::Bind(Fb303ServerThreadStackSizeMb, ini, config,
"Fb303Server.ThreadStackSizeMb", 8);
Config::Bind(Fb303ServerWorkerThreads, ini, config,
"Fb303Server.WorkerThreads", 1);
Config::Bind(Fb303ServerPoolThreads, ini, config, "Fb303Server.PoolThreads",
1);
}
#endif
{
// Xenon
Config::Bind(XenonPeriodSeconds, ini, config, "Xenon.Period", 0.0);
Config::Bind(XenonRequestFreq, ini, config, "Xenon.RequestFreq", 1);
Config::Bind(XenonForceAlwaysOn, ini, config, "Xenon.ForceAlwaysOn", false);
}
{
// Strobelight
Config::Bind(StrobelightEnabled, ini, config, "Strobelight.Enabled", false);
}
{
// Profiling
Config::Bind(SetProfileNullThisObject, ini, config,
"SetProfile.NullThisObject", true);
}
{
// Loadhint queue penalty
Config::Bind(ApplySecondaryQueuePenalty, ini, config, "Server.ApplySecondaryQueuePenalty", false);
}
Config::Bind(TzdataSearchPaths, ini, config, "TzdataSearchPaths");
Config::Bind(CustomSettings, ini, config, "CustomSettings");
// Run initializers depedent on options, e.g., resizing atomic maps/vectors.
refineStaticStringTableSize();
InitFiniNode::ProcessPostRuntimeOptions();
// **************************************************************************
// DANGER
//
// Do not bind any PHP_INI_ALL, PHP_INI_USER or PHP_INI_PERDIR settings here!
// These settings are process-wide, while those need to be thread-local since
// they are per-request. They should go into RequestInjectionData. Getting
// this wrong will cause subtle breakage -- in particular, it probably will
// not show up in CLI mode, since everything there tends to be single
// theaded.
// **************************************************************************
// Language and Misc Configuration Options
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_ONLY, "expose_php",
&RuntimeOption::ExposeHPHP);
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"auto_prepend_file", &RuntimeOption::AutoPrependFile);
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"auto_append_file", &RuntimeOption::AutoAppendFile);
// Data Handling
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"post_max_size",
IniSetting::SetAndGet<int64_t>(
nullptr,
[]() {
return VirtualHost::GetMaxPostSize();
}
),
&RuntimeOption::MaxPostSize);
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"always_populate_raw_post_data",
&RuntimeOption::AlwaysPopulateRawPostData);
// Paths and Directories
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"doc_root", &RuntimeOption::SourceRoot);
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"sendmail_path", &RuntimeOption::SendmailPath);
// FastCGI
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_ONLY,
"pid", &RuntimeOption::PidFile);
// File Uploads
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"file_uploads", "true",
&RuntimeOption::EnableFileUploads);
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"upload_tmp_dir", &RuntimeOption::UploadTmpDir);
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"upload_max_filesize",
IniSetting::SetAndGet<std::string>(
[](const std::string& value) {
return ini_on_update(
value, RuntimeOption::UploadMaxFileSize);
},
[]() {
return convert_long_to_bytes(
VirtualHost::GetUploadMaxFileSize());
}
));
// Filesystem and Streams Configuration Options
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"allow_url_fopen",
IniSetting::SetAndGet<std::string>(
[](const std::string& /*value*/) { return false; },
[]() { return "1"; }));
// HPHP specific
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_NONE,
"hphp.compiler_id",
IniSetting::SetAndGet<std::string>(
[](const std::string& /*value*/) { return false; },
[]() { return compilerId().begin(); }));
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_NONE,
"hphp.compiler_timestamp",
IniSetting::SetAndGet<int64_t>(
[](const int64_t& /*value*/) { return false; },
[]() { return compilerTimestamp(); }));
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_NONE,
"hphp.compiler_version",
IniSetting::SetAndGet<std::string>(
[](const std::string& /*value*/) { return false; },
[]() { return getHphpCompilerVersion(); }));
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_NONE,
"hphp.cli_server_api_version",
IniSetting::SetAndGet<uint64_t>(
[](const uint64_t /*value*/) { return false; },
[]() { return cli_server_api_version(); }));
IniSetting::Bind(
IniSetting::CORE, IniSetting::PHP_INI_NONE, "hphp.build_id",
IniSetting::SetAndGet<std::string>(
[](const std::string& /*value*/) { return false; }, nullptr),
&RuntimeOption::BuildId);
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"notice_frequency",
&RuntimeOption::NoticeFrequency);
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
"warning_frequency",
&RuntimeOption::WarningFrequency);
IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_ONLY,
"hhvm.build_type",
IniSetting::SetAndGet<std::string>(
[](const std::string&) {
return false;
},
[]() {
return s_hhvm_build_type.c_str();
}
));
// Extensions
Config::Bind(RuntimeOption::ExtensionDir, ini, config, "extension_dir",
RuntimeOption::ExtensionDir, false);
Config::Bind(RuntimeOption::DynamicExtensionPath, ini,
config, "DynamicExtensionPath",
RuntimeOption::DynamicExtensionPath);
Config::Bind(RuntimeOption::Extensions, ini, config, "extensions");
Config::Bind(RuntimeOption::DynamicExtensions, ini,
config, "DynamicExtensions");
ExtensionRegistry::moduleLoad(ini, config);
initialize_apc();
if (TraceFunctions.size()) Trace::ensureInit(getTraceOutputFile());
if (RO::EvalJitEnableRenameFunction && RO::RepoAuthoritative) {
throw std::runtime_error("Can't use Eval.JitEnableRenameFunction if "
" RepoAuthoritative is turned on");
}
// Bespoke array-likes
auto const enable_logging = RO::EvalBespokeArrayLikeMode != 0;
bespoke::setLoggingEnabled(enable_logging);
specializeVanillaDestructors();
// Coeffects
CoeffectsConfig::init(RO::EvalCoeffectEnforcementLevels);
// Initialize defaults for repo-specific parser configuration options.
RepoOptions::setDefaults(config, ini);
}
///////////////////////////////////////////////////////////////////////////////
uintptr_t lowArenaMinAddr() {
const char* str = getenv("HHVM_LOW_ARENA_START");
if (str == nullptr) {
#ifndef INSTRUMENTED_BUILD
return 1u << 30;
#else
return 1u << 31;
#endif
}
uintptr_t start = 0;
if (sscanf(str, "0x%lx", &start) == 1) return start;
if (sscanf(str, "%lu", &start) == 1) return start;
fprintf(stderr, "Bad environment variable HHVM_LOW_ARENA_START: %s\n", str);
abort();
}
///////////////////////////////////////////////////////////////////////////////
}