Comparar commits
29 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| e8141ac49d | |||
| 4cf537888b | |||
| 2752b5bbb1 | |||
| cc6cbf3852 | |||
| 1a4fac8a25 | |||
| ae6443500e | |||
| e42452e4f2 | |||
| 1dd7e6165e | |||
| 01ef59346e | |||
| 9380a44469 | |||
| 3f859af167 | |||
| 55ecfbdbb6 | |||
| f951cb8d88 | |||
| 2a3225ecd0 | |||
| 65cfdabb76 | |||
| 25a26c6bd7 | |||
| 3effbfe5d1 | |||
| 3a708166b8 | |||
| 3c17422435 | |||
| d3f23f393f | |||
| 3fa32fab6e | |||
| 075cb79c9f | |||
| a1f2c80031 | |||
| 4e791cc4b6 | |||
| e62e500a84 | |||
| bab7343e83 | |||
| ef3d8e9fc5 | |||
| 9401291363 | |||
| f0665f2e92 |
@@ -4251,7 +4251,9 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
e.AKExists();
|
||||
return true;
|
||||
}
|
||||
} else if (call->isCallToFunction("idx") && call->isOptimizable()) {
|
||||
} else if (call->isCallToFunction("idx") &&
|
||||
call->isOptimizable() &&
|
||||
!Option::JitEnableRenameFunction) {
|
||||
if (params && (params->getCount() == 2 || params->getCount() == 3)) {
|
||||
visit((*params)[0]);
|
||||
emitConvertToCell(e);
|
||||
|
||||
@@ -70,7 +70,7 @@ const StaticString
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef smart::unique_ptr<CufIter>::type SmartCufIterPtr;
|
||||
typedef smart::unique_ptr<CufIter> SmartCufIterPtr;
|
||||
|
||||
bool array_is_valid_callback(CArrRef arr) {
|
||||
if (arr.size() != 2 || !arr.exists(int64_t(0)) || !arr.exists(int64_t(1))) {
|
||||
|
||||
@@ -339,13 +339,13 @@ class AutoloadHandler : public RequestEventHandler {
|
||||
struct HandlerBundle {
|
||||
HandlerBundle() = delete;
|
||||
HandlerBundle(CVarRef handler,
|
||||
smart::unique_ptr<CufIter>::type& cufIter) :
|
||||
smart::unique_ptr<CufIter>& cufIter) :
|
||||
m_handler(handler) {
|
||||
m_cufIter = std::move(cufIter);
|
||||
}
|
||||
|
||||
Variant m_handler; // used to respond to f_spl_autoload_functions
|
||||
smart::unique_ptr<CufIter>::type m_cufIter; // used to invoke handlers
|
||||
smart::unique_ptr<CufIter> m_cufIter; // used to invoke handlers
|
||||
};
|
||||
|
||||
class CompareBundles {
|
||||
|
||||
@@ -443,6 +443,9 @@ static void pcre_log_error(const char *func, int line, int pcre_code,
|
||||
const char *repl, int repl_size,
|
||||
int arg1 = 0, int arg2 = 0,
|
||||
int arg3 = 0, int arg4 = 0) {
|
||||
if (!RuntimeOption::EnableHipHopSyntax) {
|
||||
return;
|
||||
}
|
||||
const char *escapedPattern;
|
||||
const char *escapedSubject;
|
||||
const char *escapedRepl;
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "hphp/runtime/base/simple-counter.h"
|
||||
#include "hphp/runtime/base/extended-logger.h"
|
||||
#include "hphp/runtime/base/stream-wrapper-registry.h"
|
||||
#include "hphp/runtime/vm/debug/debug.h"
|
||||
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/positional_options.hpp>
|
||||
@@ -624,6 +625,7 @@ hugifyText(char* from, char* to) {
|
||||
mprotect(from, sz, PROT_READ | PROT_EXEC);
|
||||
free(mem);
|
||||
mlock(from, to - from);
|
||||
Debug::DebugInfo::setPidMapOverlay(from, to);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -110,24 +110,18 @@ struct Allocator {
|
||||
};
|
||||
|
||||
/*
|
||||
* Shorthand to create a std::unique_ptr to a smart-allocated object.
|
||||
* Shorthand to create a smart::unique_ptr to a smart-allocated object.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* auto ptr = smart::make_unique<Foo>(arg1, arg2);
|
||||
*
|
||||
* If you need to make a typedef to one, since we don't have type
|
||||
* aliases yet in our version of gcc you have to do:
|
||||
*
|
||||
* typedef smart::unique_ptr<T>::type type;
|
||||
*/
|
||||
|
||||
template<class T> struct unique_ptr
|
||||
: folly::AllocatorUniquePtr<T,Allocator<T>>
|
||||
{};
|
||||
template<class T>
|
||||
using unique_ptr = typename folly::AllocatorUniquePtr<T,Allocator<T>>::type;
|
||||
|
||||
template<class T, class... Args>
|
||||
typename unique_ptr<T>::type make_unique(Args&&... args) {
|
||||
unique_ptr<T> make_unique(Args&&... args) {
|
||||
return folly::allocate_unique<T>(
|
||||
Allocator<T>(),
|
||||
std::forward<Args>(args)...
|
||||
@@ -136,7 +130,7 @@ typename unique_ptr<T>::type make_unique(Args&&... args) {
|
||||
|
||||
#ifndef __APPLE__ // XXX: this affects codegen quality but not correctness
|
||||
static_assert(
|
||||
sizeof(unique_ptr<int>::type) == sizeof(std::unique_ptr<int>),
|
||||
sizeof(unique_ptr<int>) == sizeof(std::unique_ptr<int>),
|
||||
"smart::unique_ptr pointer should not be larger than std::unique_ptr"
|
||||
);
|
||||
#endif
|
||||
|
||||
@@ -926,13 +926,6 @@ c_PDO::c_PDO(Class* cb) : ExtObjectData(cb) {
|
||||
c_PDO::~c_PDO() {
|
||||
}
|
||||
|
||||
void c_PDO::sweep() {
|
||||
// PDOConnection is not sweepable, so clean it up manually.
|
||||
static_assert(!std::is_base_of<Sweepable, PDOConnection>::value,
|
||||
"Remove the call to reset() below.");
|
||||
m_dbh.detach();
|
||||
}
|
||||
|
||||
void c_PDO::t___construct(const String& dsn, const String& username /* = null_string */,
|
||||
const String& password /* = null_string */,
|
||||
CArrRef options /* = null_array */) {
|
||||
@@ -2642,10 +2635,6 @@ c_PDOStatement::~c_PDOStatement() {
|
||||
m_row.reset();
|
||||
}
|
||||
|
||||
void c_PDOStatement::sweep() {
|
||||
// No resources allocated outside HHVM's control
|
||||
}
|
||||
|
||||
Variant c_PDOStatement::t_execute(CArrRef params /* = null_array */) {
|
||||
SYNC_VM_REGS_SCOPED();
|
||||
strcpy(m_stmt->error_code, PDO_ERR_NONE);
|
||||
|
||||
@@ -112,9 +112,9 @@ extern const int64_t q_PDO$$MYSQL_ATTR_IGNORE_SPACE;
|
||||
// class PDO
|
||||
|
||||
FORWARD_DECLARE_CLASS(PDO);
|
||||
class c_PDO : public ExtObjectData, public Sweepable {
|
||||
class c_PDO : public ExtObjectData {
|
||||
public:
|
||||
DECLARE_CLASS(PDO)
|
||||
DECLARE_CLASS_NO_SWEEP(PDO)
|
||||
|
||||
// need to implement
|
||||
public: c_PDO(Class* cls = c_PDO::classof());
|
||||
@@ -152,9 +152,9 @@ class c_PDO : public ExtObjectData, public Sweepable {
|
||||
// class PDOStatement
|
||||
|
||||
FORWARD_DECLARE_CLASS(PDOStatement);
|
||||
class c_PDOStatement : public ExtObjectData, public Sweepable {
|
||||
class c_PDOStatement : public ExtObjectData {
|
||||
public:
|
||||
DECLARE_CLASS(PDOStatement)
|
||||
DECLARE_CLASS_NO_SWEEP(PDOStatement)
|
||||
|
||||
// need to implement
|
||||
public: c_PDOStatement(Class* cls = c_PDOStatement::classof());
|
||||
|
||||
@@ -1244,6 +1244,9 @@ void c_LibXMLError::t___construct() {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// libxml
|
||||
|
||||
static xmlParserInputBufferPtr
|
||||
hphp_libxml_input_buffer(const char *URI, xmlCharEncoding enc);
|
||||
|
||||
class xmlErrorVec : public std::vector<xmlError> {
|
||||
public:
|
||||
~xmlErrorVec() {
|
||||
@@ -1263,13 +1266,15 @@ public:
|
||||
virtual void requestInit() {
|
||||
m_use_error = false;
|
||||
m_errors.reset();
|
||||
xmlParserInputBufferCreateFilenameDefault(nullptr);
|
||||
m_entity_loader_disabled = false;
|
||||
xmlParserInputBufferCreateFilenameDefault(hphp_libxml_input_buffer);
|
||||
}
|
||||
virtual void requestShutdown() {
|
||||
m_use_error = false;
|
||||
m_errors.reset();
|
||||
}
|
||||
|
||||
bool m_entity_loader_disabled;
|
||||
bool m_use_error;
|
||||
xmlErrorVec m_errors;
|
||||
};
|
||||
@@ -1376,19 +1381,19 @@ void f_libxml_set_streams_context(CResRef streams_context) {
|
||||
}
|
||||
|
||||
static xmlParserInputBufferPtr
|
||||
hphp_libxml_input_buffer_noload(const char *URI, xmlCharEncoding enc) {
|
||||
return nullptr;
|
||||
hphp_libxml_input_buffer(const char *URI, xmlCharEncoding enc) {
|
||||
if (s_libxml_errors->m_entity_loader_disabled) {
|
||||
return nullptr;
|
||||
}
|
||||
return __xmlParserInputBufferCreateFilename(URI, enc);
|
||||
}
|
||||
|
||||
bool f_libxml_disable_entity_loader(bool disable /* = true */) {
|
||||
xmlParserInputBufferCreateFilenameFunc old;
|
||||
bool old = s_libxml_errors->m_entity_loader_disabled;
|
||||
|
||||
if (disable) {
|
||||
old = xmlParserInputBufferCreateFilenameDefault(hphp_libxml_input_buffer_noload);
|
||||
} else {
|
||||
old = xmlParserInputBufferCreateFilenameDefault(nullptr);
|
||||
}
|
||||
return (old == hphp_libxml_input_buffer_noload);
|
||||
s_libxml_errors->m_entity_loader_disabled = disable;
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -72,6 +72,12 @@ PDOConnection::PDOConnection()
|
||||
PDOConnection::~PDOConnection() {
|
||||
}
|
||||
|
||||
void PDOConnection::sweep() {
|
||||
assert(!is_persistent);
|
||||
def_stmt_ctor_args.asTypedValue()->m_type = KindOfNull;
|
||||
delete this;
|
||||
}
|
||||
|
||||
void PDOConnection::persistentSave() {
|
||||
String serialized = f_serialize(def_stmt_ctor_args);
|
||||
serialized_def_stmt_ctor_args = string(serialized.data(), serialized.size());
|
||||
|
||||
@@ -235,7 +235,7 @@ class PDOStatement;
|
||||
typedef SmartResource<PDOStatement> sp_PDOStatement;
|
||||
|
||||
/* represents a connection to a database */
|
||||
class PDOConnection : public ResourceData {
|
||||
class PDOConnection : public SweepableResourceData {
|
||||
public:
|
||||
static const char *PersistentKey;
|
||||
|
||||
@@ -259,6 +259,7 @@ public:
|
||||
PDOConnection();
|
||||
virtual ~PDOConnection();
|
||||
virtual bool create(CArrRef options) = 0;
|
||||
virtual void sweep();
|
||||
|
||||
CLASSNAME_IS("PDOConnection")
|
||||
// overriding ResourceData
|
||||
|
||||
@@ -114,6 +114,15 @@ bool PDOSqliteConnection::create(CArrRef options) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void PDOSqliteConnection::sweep() {
|
||||
for (auto& udf : m_udfs) {
|
||||
udf->func.asTypedValue()->m_type = KindOfNull;
|
||||
udf->step.asTypedValue()->m_type = KindOfNull;
|
||||
udf->fini.asTypedValue()->m_type = KindOfNull;
|
||||
}
|
||||
PDOConnection::sweep();
|
||||
}
|
||||
|
||||
bool PDOSqliteConnection::support(SupportedMethod method) {
|
||||
return method != MethodCheckLiveness;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
PDOSqliteConnection();
|
||||
virtual ~PDOSqliteConnection();
|
||||
virtual bool create(CArrRef options);
|
||||
virtual void sweep();
|
||||
|
||||
int handleError(const char *file, int line, PDOStatement *stmt = nullptr);
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "hphp/runtime/ext/thrift/transport.h"
|
||||
#include "hphp/runtime/ext/ext_thrift.h"
|
||||
#include "hphp/runtime/ext/ext_class.h"
|
||||
#include "hphp/runtime/ext/ext_collections.h"
|
||||
#include "hphp/runtime/ext/ext_reflection.h"
|
||||
#include "hphp/runtime/base/base-includes.h"
|
||||
#include "hphp/util/logger.h"
|
||||
@@ -44,8 +43,6 @@ StaticString PHPTransport::s_type("type");
|
||||
StaticString PHPTransport::s_ktype("ktype");
|
||||
StaticString PHPTransport::s_vtype("vtype");
|
||||
StaticString PHPTransport::s_etype("etype");
|
||||
StaticString PHPTransport::s_format("format");
|
||||
StaticString PHPTransport::s_collection("collection");
|
||||
|
||||
|
||||
IMPLEMENT_DEFAULT_EXTENSION(thrift_protocol);
|
||||
@@ -189,13 +186,7 @@ Variant binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport,
|
||||
AccessFlags::Error_Key).toArray();
|
||||
Array valspec = fieldspec.rvalAt(PHPTransport::s_val,
|
||||
AccessFlags::Error_Key).toArray();
|
||||
String format = fieldspec.rvalAt(PHPTransport::s_format,
|
||||
AccessFlags::None).toString();
|
||||
if (format.equal(PHPTransport::s_collection)) {
|
||||
ret = NEWOBJ(c_Map)();
|
||||
} else {
|
||||
ret = Array::Create();
|
||||
}
|
||||
ret = Array::Create();
|
||||
|
||||
for (uint32_t s = 0; s < size; ++s) {
|
||||
Variant key = binary_deserialize(types[0], transport, keyspec);
|
||||
@@ -210,13 +201,7 @@ Variant binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport,
|
||||
Variant elemvar = fieldspec.rvalAt(PHPTransport::s_elem,
|
||||
AccessFlags::Error_Key);
|
||||
Array elemspec = elemvar.toArray();
|
||||
String format = fieldspec.rvalAt(PHPTransport::s_format,
|
||||
AccessFlags::None).toString();
|
||||
if (format.equal(PHPTransport::s_collection)) {
|
||||
ret = NEWOBJ(c_Vector)();
|
||||
} else {
|
||||
ret = Array::Create();
|
||||
}
|
||||
ret = Array::Create();
|
||||
|
||||
for (uint32_t s = 0; s < size; ++s) {
|
||||
Variant value = binary_deserialize(type, transport, elemspec);
|
||||
@@ -233,33 +218,15 @@ Variant binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport,
|
||||
Variant elemvar = fieldspec.rvalAt(PHPTransport::s_elem,
|
||||
AccessFlags::Error_Key);
|
||||
Array elemspec = elemvar.toArray();
|
||||
String format = fieldspec.rvalAt(PHPTransport::s_format,
|
||||
AccessFlags::None).toString();
|
||||
if (format.equal(PHPTransport::s_collection)) {
|
||||
p_Set set_ret = NEWOBJ(c_Set)();
|
||||
ret = Array::Create();
|
||||
|
||||
for (uint32_t s = 0; s < size; ++s) {
|
||||
Variant key = binary_deserialize(type, transport, elemspec);
|
||||
for (uint32_t s = 0; s < size; ++s) {
|
||||
Variant key = binary_deserialize(type, transport, elemspec);
|
||||
|
||||
if (key.isInteger()) {
|
||||
set_ret->t_add(key);
|
||||
} else {
|
||||
set_ret->t_add(key.toString());
|
||||
}
|
||||
}
|
||||
|
||||
ret = Variant(set_ret);
|
||||
} else {
|
||||
ret = Array::Create();
|
||||
|
||||
for (uint32_t s = 0; s < size; ++s) {
|
||||
Variant key = binary_deserialize(type, transport, elemspec);
|
||||
|
||||
if (key.isInteger()) {
|
||||
ret.set(key, true);
|
||||
} else {
|
||||
ret.set(key.toString(), true);
|
||||
}
|
||||
if (key.isInteger()) {
|
||||
ret.set(key, true);
|
||||
} else {
|
||||
ret.set(key.toString(), true);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "hphp/runtime/base/request-local.h"
|
||||
#include "hphp/runtime/ext/thrift/transport.h"
|
||||
#include "hphp/runtime/ext/ext_collections.h"
|
||||
#include "hphp/runtime/ext/ext_reflection.h"
|
||||
#include "hphp/runtime/ext/ext_thrift.h"
|
||||
|
||||
@@ -710,10 +709,10 @@ class CompactReader {
|
||||
return readMap(spec);
|
||||
|
||||
case T_LIST:
|
||||
return readList(spec);
|
||||
return readList(spec, C_LIST_LIST);
|
||||
|
||||
case T_SET:
|
||||
return readSet(spec);
|
||||
return readList(spec, C_LIST_SET);
|
||||
|
||||
default:
|
||||
throw InvalidArgumentException("unknown TType", type);
|
||||
@@ -824,14 +823,7 @@ class CompactReader {
|
||||
AccessFlags::Error).toArray();
|
||||
Array valueSpec = spec.rvalAt(PHPTransport::s_val,
|
||||
AccessFlags::Error).toArray();
|
||||
String format = spec.rvalAt(PHPTransport::s_format,
|
||||
AccessFlags::None).toString();
|
||||
Variant ret;
|
||||
if (format.equal(PHPTransport::s_collection)) {
|
||||
ret = NEWOBJ(c_Map)();
|
||||
} else {
|
||||
ret = Array::Create();
|
||||
}
|
||||
Variant ret = Array::Create();
|
||||
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
Variant key = readField(keySpec, keyType);
|
||||
@@ -843,60 +835,24 @@ class CompactReader {
|
||||
return ret;
|
||||
}
|
||||
|
||||
Variant readList(CArrRef spec) {
|
||||
Variant readList(CArrRef spec, CListType listType) {
|
||||
TType valueType;
|
||||
uint32_t size;
|
||||
readListBegin(valueType, size);
|
||||
|
||||
Array valueSpec = spec.rvalAt(PHPTransport::s_elem,
|
||||
AccessFlags::Error_Key).toArray();
|
||||
String format = spec.rvalAt(PHPTransport::s_format,
|
||||
AccessFlags::None).toString();
|
||||
Variant ret;
|
||||
if (format.equal(PHPTransport::s_collection)) {
|
||||
ret = NEWOBJ(c_Vector)();
|
||||
} else {
|
||||
ret = Array::Create();
|
||||
}
|
||||
Variant ret = Array::Create();
|
||||
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
Variant value = readField(valueSpec, valueType);
|
||||
ret.append(value);
|
||||
}
|
||||
|
||||
readCollectionEnd();
|
||||
return ret;
|
||||
}
|
||||
|
||||
Variant readSet(CArrRef spec) {
|
||||
TType valueType;
|
||||
uint32_t size;
|
||||
readListBegin(valueType, size);
|
||||
|
||||
Array valueSpec = spec.rvalAt(PHPTransport::s_elem,
|
||||
AccessFlags::Error_Key).toArray();
|
||||
String format = spec.rvalAt(PHPTransport::s_format,
|
||||
AccessFlags::None).toString();
|
||||
Variant ret;
|
||||
if (format.equal(PHPTransport::s_collection)) {
|
||||
p_Set set_ret = NEWOBJ(c_Set)();
|
||||
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
Variant value = readField(valueSpec, valueType);
|
||||
set_ret->t_add(value);
|
||||
}
|
||||
|
||||
ret = Variant(set_ret);
|
||||
} else {
|
||||
ret = Array::Create();
|
||||
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
Variant value = readField(valueSpec, valueType);
|
||||
if (listType == C_LIST_LIST) {
|
||||
ret.append(value);
|
||||
} else {
|
||||
ret.set(value, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
readCollectionEnd();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -105,8 +105,6 @@ public:
|
||||
static StaticString s_ktype;
|
||||
static StaticString s_vtype;
|
||||
static StaticString s_etype;
|
||||
static StaticString s_format;
|
||||
static StaticString s_collection;
|
||||
|
||||
public:
|
||||
Object protocol() { return p; }
|
||||
|
||||
@@ -62,7 +62,8 @@ void FastCGIAcceptor::onNewConnection(
|
||||
localAddress = s_unknownSocketAddress;
|
||||
}
|
||||
|
||||
FastCGIConnection* conn = new FastCGIConnection(
|
||||
// Will delete itself when it gets a closing callback
|
||||
auto conn = new FastCGIConnection(
|
||||
m_server,
|
||||
std::move(sock),
|
||||
localAddress,
|
||||
@@ -145,6 +146,7 @@ void FastCGIConnection::onSessionError() {
|
||||
|
||||
void FastCGIConnection::onSessionClose() {
|
||||
shutdownTransport();
|
||||
delete this;
|
||||
}
|
||||
|
||||
void FastCGIConnection::setMaxConns(int max_conns) {
|
||||
|
||||
@@ -527,8 +527,8 @@ void FastCGISession::handleStdErr(RequestId request_id,
|
||||
}
|
||||
|
||||
void FastCGISession::handleComplete(RequestId request_id) {
|
||||
writeEndRequest(request_id, 0, ProtoStatus::REQUEST_COMPLETE);
|
||||
endTransaction(request_id);
|
||||
writeEndRequest(request_id, 0, ProtoStatus::REQUEST_COMPLETE);
|
||||
if (!m_keepConn) {
|
||||
handleClose();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "hphp/runtime/server/fastcgi/fastcgi-transport.h"
|
||||
#include "hphp/runtime/server/fastcgi/fastcgi-server.h"
|
||||
#include "hphp/runtime/server/transport.h"
|
||||
#include "hphp/runtime/base/runtime-error.h"
|
||||
#include "folly/io/IOBuf.h"
|
||||
#include "folly/io/IOBufQueue.h"
|
||||
#include "thrift/lib/cpp/async/TAsyncTransport.h"
|
||||
@@ -27,6 +28,9 @@
|
||||
#include "hphp/util/timer.h"
|
||||
#include "folly/MoveWrapper.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
using folly::IOBuf;
|
||||
using folly::IOBufQueue;
|
||||
using folly::io::Cursor;
|
||||
@@ -39,22 +43,48 @@ namespace HPHP {
|
||||
FastCGITransport::FastCGITransport(FastCGIConnection* connection, int id)
|
||||
: m_connection(connection),
|
||||
m_id(id),
|
||||
m_remotePort(0), m_method(Method::Unknown), m_requestSize(0),
|
||||
m_headersSent(false), m_readMore(false),
|
||||
m_waiting(0), m_readComplete(false) {}
|
||||
m_remotePort(0),
|
||||
m_serverPort(0),
|
||||
m_method(Method::Unknown),
|
||||
m_requestSize(0),
|
||||
m_headersSent(false),
|
||||
m_readMore(false),
|
||||
m_waiting(0),
|
||||
m_readComplete(false) {}
|
||||
|
||||
const char *FastCGITransport::getUrl() {
|
||||
return m_requestURI.c_str();
|
||||
}
|
||||
|
||||
const std::string FastCGITransport::getDocumentRoot() {
|
||||
return m_documentRoot;
|
||||
}
|
||||
|
||||
const char *FastCGITransport::getRemoteHost() {
|
||||
return m_remoteHost.c_str();
|
||||
}
|
||||
|
||||
const char *FastCGITransport::getRemoteAddr() {
|
||||
return m_remoteAddr.c_str();
|
||||
}
|
||||
|
||||
uint16_t FastCGITransport::getRemotePort() {
|
||||
return m_remotePort;
|
||||
}
|
||||
|
||||
const char *FastCGITransport::getServerName() {
|
||||
return m_serverName.c_str();
|
||||
}
|
||||
|
||||
const char *FastCGITransport::getServerAddr() {
|
||||
return (!m_serverAddr.empty()) ? m_serverAddr.c_str() :
|
||||
Transport::getServerAddr();
|
||||
}
|
||||
|
||||
uint16_t FastCGITransport::getServerPort() {
|
||||
return (m_serverPort != 0) ? m_serverPort : Transport::getServerPort();
|
||||
}
|
||||
|
||||
const void *FastCGITransport::getPostData(int &size) {
|
||||
DCHECK(!m_readMore);
|
||||
return getPostDataImpl(size, false);
|
||||
@@ -127,7 +157,48 @@ const char *FastCGITransport::getServerObject() {
|
||||
return m_serverObject.c_str();
|
||||
}
|
||||
|
||||
std::string FastCGITransport::unmangleHeader(const std::string& name) {
|
||||
if (!boost::istarts_with(name, "HTTP_")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string ret;
|
||||
bool is_upper = true;
|
||||
for (auto& c : name.substr(5)) {
|
||||
if (c == '_') {
|
||||
ret += '-';
|
||||
is_upper = true;
|
||||
} else {
|
||||
ret += is_upper ? toupper(c) : tolower(c);
|
||||
is_upper = false;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string FastCGITransport::mangleHeader(const std::string& name) {
|
||||
std::string ret;
|
||||
for (auto& c : name) {
|
||||
if (c == '-') {
|
||||
ret += '_';
|
||||
} else {
|
||||
ret += toupper(c);
|
||||
}
|
||||
}
|
||||
return "HTTP_" + ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Passed an HTTP header like "Cookie" or "Cache-Control"
|
||||
**/
|
||||
std::string FastCGITransport::getHeader(const char *name) {
|
||||
return getRawHeader(mangleHeader(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Passed a FastCGI mangled header like "HTTP_COOKIE" or "HTTP_CACHE_CONTROL"
|
||||
**/
|
||||
std::string FastCGITransport::getRawHeader(const std::string& name) {
|
||||
if (m_requestHeaders.count(name) && m_requestHeaders[name].size()) {
|
||||
return m_requestHeaders[name][0];
|
||||
} else {
|
||||
@@ -136,12 +207,22 @@ std::string FastCGITransport::getHeader(const char *name) {
|
||||
}
|
||||
|
||||
void FastCGITransport::getHeaders(HeaderMap &headers) {
|
||||
headers = m_requestHeaders;
|
||||
for (auto& pair : m_requestHeaders) {
|
||||
auto key = unmangleHeader(pair.first);
|
||||
if (!key.empty()) {
|
||||
headers[key] = pair.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FastCGITransport::getTransportParams(HeaderMap &serverParams) {
|
||||
for (auto& pair : m_requestHeaders) {
|
||||
serverParams[pair.first] = pair.second;
|
||||
}
|
||||
}
|
||||
|
||||
void FastCGITransport::addHeaderImpl(const char *name, const char *value) {
|
||||
CHECK(!m_headersSent);
|
||||
|
||||
if (!m_responseHeaders.count(name)) {
|
||||
m_responseHeaders.insert(std::make_pair(name,
|
||||
std::vector<std::string>()));
|
||||
@@ -221,10 +302,16 @@ void FastCGITransport::onBodyComplete() {
|
||||
|
||||
const std::string FastCGITransport::k_requestURIKey = "REQUEST_URI";
|
||||
const std::string FastCGITransport::k_remoteHostKey = "REMOTE_HOST";
|
||||
const std::string FastCGITransport::k_remoteAddrKey = "REMOTE_ADDR";
|
||||
const std::string FastCGITransport::k_remotePortKey = "REMOTE_PORT";
|
||||
const std::string FastCGITransport::k_methodKey = "REQUEST_METHOD";
|
||||
const std::string FastCGITransport::k_httpVersionKey = "HTTP_VERSION";
|
||||
const std::string FastCGITransport::k_contentLengthKey = "CONTENT_LENGTH";
|
||||
const std::string FastCGITransport::k_documentRoot = "DOCUMENT_ROOT";
|
||||
const std::string FastCGITransport::k_serverNameKey = "SERVER_NAME";
|
||||
const std::string FastCGITransport::k_serverPortKey = "SERVER_PORT";
|
||||
const std::string FastCGITransport::k_serverAddrKey = "SERVER_ADDR";
|
||||
const std::string FastCGITransport::k_httpsKey = "HTTPS";
|
||||
|
||||
void FastCGITransport::onHeader(std::unique_ptr<folly::IOBuf> key_chain,
|
||||
std::unique_ptr<folly::IOBuf> value_chain) {
|
||||
@@ -254,6 +341,8 @@ void FastCGITransport::handleHeader(const std::string& key,
|
||||
m_requestURI = value;
|
||||
} else if (compareKeys(key, k_remoteHostKey)) {
|
||||
m_remoteHost = value;
|
||||
} else if (compareKeys(key, k_remoteAddrKey)) {
|
||||
m_remoteAddr = value;
|
||||
} else if (compareKeys(key, k_remotePortKey)) {
|
||||
try {
|
||||
int remote_port = std::stoi(value);
|
||||
@@ -267,6 +356,27 @@ void FastCGITransport::handleHeader(const std::string& key,
|
||||
} catch (std::out_of_range&) {
|
||||
m_remotePort = 0;
|
||||
}
|
||||
} else if (compareKeys(key, k_serverNameKey)) {
|
||||
m_serverName = value;
|
||||
} else if (compareKeys(key, k_httpsKey)) {
|
||||
if (!value.empty()) {
|
||||
std::string lValue(value);
|
||||
boost::to_lower(lValue);
|
||||
// IIS sets this value but sets it to off when SSL is off.
|
||||
if (lValue.compare("off") != 0) {
|
||||
setSSL();
|
||||
}
|
||||
}
|
||||
} else if (compareKeys(key, k_serverAddrKey)) {
|
||||
m_serverAddr = value;
|
||||
} else if (compareKeys(key, k_serverPortKey)) {
|
||||
try {
|
||||
m_serverPort = std::stoi(value);
|
||||
} catch (std::invalid_argument&) {
|
||||
m_serverPort = 0;
|
||||
} catch (std::out_of_range&) {
|
||||
m_serverPort = 0;
|
||||
}
|
||||
} else if (compareKeys(key, k_methodKey)) {
|
||||
m_extendedMethod = value;
|
||||
if (compareValues(value, "GET")) {
|
||||
@@ -288,12 +398,23 @@ void FastCGITransport::handleHeader(const std::string& key,
|
||||
} catch (std::out_of_range&) {
|
||||
m_requestSize = 0;
|
||||
}
|
||||
} else if (compareKeys(key, k_documentRoot)) {
|
||||
m_documentRoot = value + "/";
|
||||
}
|
||||
}
|
||||
|
||||
void FastCGITransport::onHeadersComplete() {
|
||||
m_serverObject = getHeader("SCRIPT_NAME");
|
||||
std::string queryString = getHeader("QUERY_STRING");
|
||||
std::string pathTranslated = getRawHeader("PATH_TRANSLATED");
|
||||
std::string documentRoot = getRawHeader("DOCUMENT_ROOT");
|
||||
// use PATH_TRANSLATED - DOCUMENT_ROOT if it is valid instead of SCRIPT_NAME
|
||||
// for mod_fastcgi support
|
||||
if (!pathTranslated.empty() && !documentRoot.empty() &&
|
||||
pathTranslated.find(documentRoot) == 0) {
|
||||
m_serverObject = pathTranslated.substr(documentRoot.length());
|
||||
} else {
|
||||
m_serverObject = getRawHeader("SCRIPT_NAME");
|
||||
}
|
||||
std::string queryString = getRawHeader("QUERY_STRING");
|
||||
if (!queryString.empty()) {
|
||||
m_serverObject += "?" + queryString;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,12 @@ public:
|
||||
|
||||
virtual const char *getUrl() override;
|
||||
virtual const char *getRemoteHost() override;
|
||||
virtual const char *getRemoteAddr() override;
|
||||
virtual uint16_t getRemotePort() override;
|
||||
virtual const std::string getDocumentRoot() override;
|
||||
virtual const char *getServerName() override;
|
||||
virtual const char *getServerAddr() override;
|
||||
virtual uint16_t getServerPort() override;
|
||||
|
||||
virtual const void *getPostData(int &size) override;
|
||||
virtual bool hasMorePostData() override;
|
||||
@@ -65,6 +70,7 @@ public:
|
||||
|
||||
virtual std::string getHeader(const char *name) override;
|
||||
virtual void getHeaders(HeaderMap &headers) override;
|
||||
virtual void getTransportParams(HeaderMap &serverParams) override;
|
||||
|
||||
virtual void addHeaderImpl(const char *name, const char *value) override;
|
||||
virtual void removeHeaderImpl(const char *name) override;
|
||||
@@ -87,6 +93,15 @@ private:
|
||||
typedef std::map<std::string, std::vector<std::string>> ResponseHeaders;
|
||||
|
||||
void handleHeader(const std::string& key, const std::string& value);
|
||||
std::string getRawHeader(const std::string& name);
|
||||
/*
|
||||
* HTTP_IF_MODIFIED_SINCE -> If-Unmodified-Since
|
||||
*/
|
||||
std::string unmangleHeader(const std::string& name);
|
||||
/*
|
||||
* If-Unmodified-Since -> HTTP_IF_MODIFIED_SINCE
|
||||
*/
|
||||
std::string mangleHeader(const std::string& name);
|
||||
|
||||
static bool compareKeys(const std::string& key,
|
||||
const std::string& other_key);
|
||||
@@ -97,10 +112,16 @@ private:
|
||||
|
||||
static const std::string k_requestURIKey;
|
||||
static const std::string k_remoteHostKey;
|
||||
static const std::string k_remoteAddrKey;
|
||||
static const std::string k_remotePortKey;
|
||||
static const std::string k_methodKey;
|
||||
static const std::string k_httpVersionKey;
|
||||
static const std::string k_contentLengthKey;
|
||||
static const std::string k_documentRoot;
|
||||
static const std::string k_serverNameKey;
|
||||
static const std::string k_serverPortKey;
|
||||
static const std::string k_serverAddrKey;
|
||||
static const std::string k_httpsKey;
|
||||
|
||||
FastCGIConnection* m_connection;
|
||||
int m_id;
|
||||
@@ -108,8 +129,13 @@ private:
|
||||
std::unique_ptr<folly::IOBuf> m_currBody;
|
||||
HeaderMap m_requestHeaders;
|
||||
std::string m_requestURI;
|
||||
std::string m_documentRoot;
|
||||
std::string m_remoteHost;
|
||||
std::string m_remoteAddr;
|
||||
uint16_t m_remotePort;
|
||||
std::string m_serverName;
|
||||
std::string m_serverAddr;
|
||||
uint16_t m_serverPort;
|
||||
Method m_method;
|
||||
std::string m_extendedMethod;
|
||||
std::string m_httpVersion;
|
||||
|
||||
@@ -323,24 +323,9 @@ bool HttpProtocol::PrepareCookieVariable(Variant& cookie,
|
||||
}
|
||||
|
||||
void HttpProtocol::CopyHeaderVariables(Variant& server,
|
||||
const HeaderMap& headers,
|
||||
bool normalize) {
|
||||
const HeaderMap& headers) {
|
||||
static std::atomic<int> badRequests(-1);
|
||||
|
||||
if (!normalize) {
|
||||
for (HeaderMap::const_iterator iter = headers.begin();
|
||||
iter != headers.end();
|
||||
++iter) {
|
||||
const vector<string> &values = iter->second;
|
||||
for (unsigned int i = 0; i < values.size(); i++) {
|
||||
String key = string_replace(f_strtoupper(iter->first), s_dash,
|
||||
s_underscore);
|
||||
server.set(key, String(values[i]));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> badHeaders;
|
||||
for (auto const& header : headers) {
|
||||
auto const& key = header.first;
|
||||
@@ -392,12 +377,35 @@ void HttpProtocol::CopyHeaderVariables(Variant& server,
|
||||
}
|
||||
}
|
||||
|
||||
void HttpProtocol::CopyTransportParams(Variant& server,
|
||||
Transport *transport) {
|
||||
HeaderMap transportParams;
|
||||
// Get additional server params from the transport if it has any. In the case
|
||||
// of fastcgi this is basically a full header list from apache/nginx.
|
||||
transport->getTransportParams(transportParams);
|
||||
for (auto const& header : transportParams) {
|
||||
auto const& key = header.first;
|
||||
auto const& values = header.second;
|
||||
auto normalizedKey = string_replace(f_strtoupper(key), s_dash,
|
||||
s_underscore);
|
||||
|
||||
// Be careful here to not overwrite any _SERVER variable
|
||||
// that has already been set elsewhere and make sure it has a value.
|
||||
if (!values.empty() && !server.asArrRef().exists(normalizedKey)) {
|
||||
// When a header has multiple values, we always take the last one.
|
||||
server.set(normalizedKey, String(values.back()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HttpProtocol::CopyServerInfo(Variant& server,
|
||||
Transport *transport,
|
||||
const VirtualHost *vhost) {
|
||||
|
||||
string hostHeader = transport->getHeader("Host");
|
||||
String hostName(vhost->serverName(hostHeader));
|
||||
String serverNameHeader(transport->getServerName());
|
||||
|
||||
if (hostHeader.empty()) {
|
||||
server.set(s_HTTP_HOST, hostName);
|
||||
@@ -405,19 +413,26 @@ void HttpProtocol::CopyServerInfo(Variant& server,
|
||||
} else {
|
||||
StackTraceNoHeap::AddExtraLogging("Server", hostHeader.c_str());
|
||||
}
|
||||
if (hostName.empty() || RuntimeOption::ForceServerNameToHeader) {
|
||||
|
||||
// Use the header from the transport if it is available
|
||||
if (!serverNameHeader.empty()) {
|
||||
hostName = serverNameHeader;
|
||||
} else if (hostName.empty() || RuntimeOption::ForceServerNameToHeader) {
|
||||
hostName = hostHeader;
|
||||
// _SERVER['SERVER_NAME'] shouldn't contain the port number
|
||||
int colonPos = hostName.find(':');
|
||||
if (colonPos != String::npos) {
|
||||
hostName = hostName.substr(0, colonPos);
|
||||
}
|
||||
}
|
||||
|
||||
// _SERVER['SERVER_NAME'] shouldn't contain the port number
|
||||
int colonPos = hostName.find(':');
|
||||
if (colonPos != String::npos) {
|
||||
hostName = hostName.substr(0, colonPos);
|
||||
}
|
||||
|
||||
StackTraceNoHeap::AddExtraLogging("Server_SERVER_NAME", hostName.data());
|
||||
|
||||
server.set(s_GATEWAY_INTERFACE, s_CGI_1_1);
|
||||
server.set(s_SERVER_ADDR, String(RuntimeOption::ServerPrimaryIP));
|
||||
server.set(s_SERVER_ADDR, transport->getServerAddr());
|
||||
server.set(s_SERVER_NAME, hostName);
|
||||
server.set(s_SERVER_PORT, RuntimeOption::ServerPort);
|
||||
server.set(s_SERVER_PORT, transport->getServerPort());
|
||||
server.set(s_SERVER_SOFTWARE, s_HPHP);
|
||||
server.set(s_SERVER_PROTOCOL, "HTTP/" + transport->getHTTPVersion());
|
||||
server.set(s_SERVER_ADMIN, empty_string);
|
||||
@@ -426,8 +441,17 @@ void HttpProtocol::CopyServerInfo(Variant& server,
|
||||
|
||||
void HttpProtocol::CopyRemoteInfo(Variant& server,
|
||||
Transport *transport) {
|
||||
server.set(s_REMOTE_ADDR, String(transport->getRemoteHost(), CopyString));
|
||||
server.set(s_REMOTE_HOST, empty_string); // I don't think we need to nslookup
|
||||
String remoteAddr(transport->getRemoteAddr(), CopyString);
|
||||
String remoteHost(transport->getRemoteHost(), CopyString);
|
||||
|
||||
if(remoteAddr.empty()) {
|
||||
remoteAddr = remoteHost;
|
||||
}
|
||||
|
||||
server.set(s_REMOTE_ADDR, remoteAddr);
|
||||
if(!remoteHost.empty()) {
|
||||
server.set(s_REMOTE_HOST, remoteHost);
|
||||
}
|
||||
server.set(s_REMOTE_PORT, transport->getRemotePort());
|
||||
}
|
||||
|
||||
@@ -515,15 +539,13 @@ void HttpProtocol::CopyPathInfo(Variant& server,
|
||||
server.set(s_PHP_SELF, r.resolvedURL() + r.origPathInfo());
|
||||
}
|
||||
|
||||
String documentRoot;
|
||||
if (RuntimeOption::ServerType != "fastcgi") {
|
||||
String documentRoot = transport->getDocumentRoot();
|
||||
if (documentRoot.empty()) {
|
||||
// Right now this is just RuntimeOption::SourceRoot but mwilliams wants to
|
||||
// fix it so it is settable, so I'll leave this for now
|
||||
documentRoot = vhost->getDocumentRoot();
|
||||
server.set(s_DOCUMENT_ROOT, documentRoot);
|
||||
} else if (server.asCArrRef().exists(s_DOCUMENT_ROOT)) {
|
||||
CHECK(server[s_DOCUMENT_ROOT].isString());
|
||||
documentRoot = server[s_DOCUMENT_ROOT].toCStrRef();
|
||||
}
|
||||
|
||||
server.set(s_DOCUMENT_ROOT, documentRoot);
|
||||
server.set(s_SCRIPT_FILENAME, r.absolutePath());
|
||||
|
||||
if (r.pathInfo().empty()) {
|
||||
@@ -590,14 +612,10 @@ void HttpProtocol::PrepareServerVariable(Variant& server,
|
||||
// "may" exclude them; this is not what APE does, but it's harmless.
|
||||
HeaderMap headers;
|
||||
transport->getHeaders(headers);
|
||||
if (RuntimeOption::ServerType != "fastcgi") {
|
||||
CopyHeaderVariables(server, headers, true);
|
||||
CopyServerInfo(server, transport, vhost);
|
||||
CopyRemoteInfo(server, transport);
|
||||
CopyAuthInfo(server, transport);
|
||||
} else {
|
||||
CopyHeaderVariables(server, headers, false);
|
||||
}
|
||||
CopyHeaderVariables(server, headers);
|
||||
CopyServerInfo(server, transport, vhost);
|
||||
CopyRemoteInfo(server, transport);
|
||||
CopyAuthInfo(server, transport);
|
||||
|
||||
CopyPathInfo(server, transport, r, vhost);
|
||||
|
||||
@@ -622,6 +640,8 @@ void HttpProtocol::PrepareServerVariable(Variant& server,
|
||||
iter != vServerVars.end(); ++iter) {
|
||||
server.set(String(iter->first), String(iter->second));
|
||||
}
|
||||
// Do this last as to not overwrite any existing server variables.
|
||||
CopyTransportParams(server, transport);
|
||||
sri.setServerVariables(server);
|
||||
|
||||
const char *threadType = transport->getThreadTypeName();
|
||||
|
||||
@@ -59,8 +59,9 @@ public:
|
||||
const SourceRootInfo &sri,
|
||||
const VirtualHost *vhost);
|
||||
static void CopyHeaderVariables(Variant& server,
|
||||
const HeaderMap& headers,
|
||||
bool normalize);
|
||||
const HeaderMap& headers);
|
||||
static void CopyTransportParams(Variant& server,
|
||||
Transport *transport);
|
||||
static void CopyServerInfo(Variant& server,
|
||||
Transport *transport,
|
||||
const VirtualHost *vhost);
|
||||
|
||||
@@ -154,8 +154,7 @@ void HttpRequestHandler::handleRequest(Transport *transport) {
|
||||
vhost->getName().c_str());
|
||||
|
||||
// resolve source root
|
||||
string host = transport->getHeader("Host");
|
||||
SourceRootInfo sourceRootInfo(host.c_str());
|
||||
SourceRootInfo sourceRootInfo(transport);
|
||||
|
||||
if (sourceRootInfo.error()) {
|
||||
sourceRootInfo.handleError(transport);
|
||||
|
||||
@@ -157,8 +157,7 @@ void RPCRequestHandler::handleRequest(Transport *transport) {
|
||||
};
|
||||
|
||||
// resolve source root
|
||||
string host = transport->getHeader("Host");
|
||||
SourceRootInfo sourceRootInfo(host.c_str());
|
||||
SourceRootInfo sourceRootInfo(transport);
|
||||
|
||||
// set thread type
|
||||
switch (m_serverInfo->getType()) {
|
||||
|
||||
@@ -30,12 +30,22 @@ namespace HPHP {
|
||||
IMPLEMENT_THREAD_LOCAL_NO_CHECK(string, SourceRootInfo::s_path);
|
||||
IMPLEMENT_THREAD_LOCAL_NO_CHECK(string, SourceRootInfo::s_phproot);
|
||||
|
||||
SourceRootInfo::SourceRootInfo(const char *host)
|
||||
SourceRootInfo::SourceRootInfo(Transport* transport)
|
||||
: m_sandboxCond(RuntimeOption::SandboxMode ? SandboxCondition::On :
|
||||
SandboxCondition::Off) {
|
||||
s_path.destroy();
|
||||
s_phproot.destroy();
|
||||
|
||||
auto documentRoot = transport->getDocumentRoot();
|
||||
if (!documentRoot.empty()) {
|
||||
// The transport take precedence over the config file
|
||||
m_path = documentRoot;
|
||||
*s_path.getCheck() = documentRoot;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sandboxOn()) return;
|
||||
auto host = transport->getHeader("Host");
|
||||
Variant matches;
|
||||
Variant r = preg_match(String(RuntimeOption::SandboxPattern.c_str(),
|
||||
RuntimeOption::SandboxPattern.size(),
|
||||
@@ -242,8 +252,7 @@ string SourceRootInfo::parseSandboxServerVariable(const string &format) const {
|
||||
}
|
||||
|
||||
string SourceRootInfo::path() const {
|
||||
if (sandboxOn()) {
|
||||
// Should return RuntimeOption::SourceRoot if m_data is empty?
|
||||
if (sandboxOn() || !m_path.empty()) {
|
||||
return string(m_path.data(), m_path.size());
|
||||
} else {
|
||||
return RuntimeOption::SourceRoot;
|
||||
|
||||
@@ -27,7 +27,7 @@ class Transport;
|
||||
|
||||
class SourceRootInfo {
|
||||
public:
|
||||
explicit SourceRootInfo(const char *host);
|
||||
explicit SourceRootInfo(Transport* transport);
|
||||
SourceRootInfo(const std::string &user, const std::string &sandbox);
|
||||
void createFromUserConfig();
|
||||
void createFromCommonRoot(const String &sandboxName);
|
||||
|
||||
@@ -84,10 +84,10 @@ public:
|
||||
virtual ~Transport();
|
||||
|
||||
void onRequestStart(const timespec &queueTime);
|
||||
const timespec &getQueueTime() const { return m_queueTime;}
|
||||
const timespec &getWallTime() const { return m_wallTime;}
|
||||
const timespec &getCpuTime() const { return m_cpuTime;}
|
||||
const int64_t &getInstructions() const { return m_instructions;}
|
||||
const timespec &getQueueTime() const { return m_queueTime; }
|
||||
const timespec &getWallTime() const { return m_wallTime; }
|
||||
const timespec &getCpuTime() const { return m_cpuTime; }
|
||||
const int64_t &getInstructions() const { return m_instructions; }
|
||||
const int64_t &getSleepTime() const { return m_sleepTime; }
|
||||
void incSleepTime(unsigned int seconds) { m_sleepTime += seconds; }
|
||||
const int64_t &getuSleepTime() const { return m_usleepTime; }
|
||||
@@ -109,6 +109,23 @@ public:
|
||||
virtual const char *getUrl() = 0;
|
||||
virtual const char *getRemoteHost() = 0;
|
||||
virtual uint16_t getRemotePort() = 0;
|
||||
// The transport can override REMOTE_ADDR if it has one
|
||||
virtual const char *getRemoteAddr() { return ""; }
|
||||
// The transport can override the virtualhosts' docroot
|
||||
virtual const std::string getDocumentRoot() { return ""; }
|
||||
|
||||
/**
|
||||
* Server Headers
|
||||
*/
|
||||
virtual const char *getServerName() {
|
||||
return "";
|
||||
};
|
||||
virtual const char *getServerAddr() {
|
||||
return RuntimeOption::ServerPrimaryIP.c_str();
|
||||
};
|
||||
virtual uint16_t getServerPort() {
|
||||
return RuntimeOption::ServerPort;
|
||||
};
|
||||
|
||||
/**
|
||||
* POST request's data.
|
||||
@@ -139,6 +156,7 @@ public:
|
||||
*/
|
||||
virtual std::string getHeader(const char *name) = 0;
|
||||
virtual void getHeaders(HeaderMap &headers) = 0;
|
||||
virtual void getTransportParams(HeaderMap &serverParams) {};
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,22 +16,28 @@
|
||||
|
||||
#include "hphp/runtime/vm/debug/debug.h"
|
||||
#include "hphp/runtime/vm/debug/gdb-jit.h"
|
||||
#include "hphp/runtime/vm/jit/translator-x64.h"
|
||||
|
||||
#include "hphp/runtime/base/execution-context.h"
|
||||
|
||||
#include "hphp/util/current-executable.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "hphp/runtime/vm/jit/translator-x64.h"
|
||||
#include <bfd.h>
|
||||
|
||||
using namespace HPHP::Transl;
|
||||
|
||||
namespace HPHP {
|
||||
namespace Debug {
|
||||
|
||||
void* DebugInfo::pidMapOverlayStart;
|
||||
void* DebugInfo::pidMapOverlayEnd;
|
||||
|
||||
DebugInfo* DebugInfo::Get() {
|
||||
return tx64->getDebugInfo();
|
||||
}
|
||||
@@ -41,6 +47,7 @@ DebugInfo::DebugInfo() {
|
||||
sizeof m_perfMapName,
|
||||
"/tmp/perf-%d.map", getpid());
|
||||
m_perfMap = fopen(m_perfMapName, "w");
|
||||
generatePidMapOverlay();
|
||||
}
|
||||
|
||||
DebugInfo::~DebugInfo() {
|
||||
@@ -50,6 +57,74 @@ DebugInfo::~DebugInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
void DebugInfo::generatePidMapOverlay() {
|
||||
if (!m_perfMap || !pidMapOverlayStart) return;
|
||||
|
||||
std::string self = current_executable_path();
|
||||
bfd* abfd = bfd_openr(self.c_str(), nullptr);
|
||||
#ifdef BFD_DECOMPRESS
|
||||
abfd->flags |= BFD_DECOMPRESS;
|
||||
#endif
|
||||
char **match = nullptr;
|
||||
if (!bfd_check_format(abfd, bfd_archive) &&
|
||||
bfd_check_format_matches(abfd, bfd_object, &match)) {
|
||||
|
||||
std::vector<asymbol*> sorted;
|
||||
long storage_needed = bfd_get_symtab_upper_bound (abfd);
|
||||
|
||||
if (storage_needed <= 0) return;
|
||||
|
||||
auto symbol_table = (asymbol**)malloc(storage_needed);
|
||||
|
||||
long number_of_symbols = bfd_canonicalize_symtab(abfd, symbol_table);
|
||||
|
||||
for (long i = 0; i < number_of_symbols; i++) {
|
||||
auto sym = symbol_table[i];
|
||||
if (!(sym->flags & (BSF_LOCAL|BSF_GLOBAL))) continue;
|
||||
if (sym->flags &
|
||||
(BSF_INDIRECT|BSF_SECTION_SYM|BSF_WEAK|BSF_FILE|BSF_OBJECT)) {
|
||||
continue;
|
||||
}
|
||||
auto sec = sym->section;
|
||||
if (!(sec->flags & (SEC_ALLOC|SEC_LOAD|SEC_CODE))) continue;
|
||||
auto addr = sec->vma + sym->value;
|
||||
if (addr < uintptr_t(pidMapOverlayStart) ||
|
||||
addr >= uintptr_t(pidMapOverlayEnd)) {
|
||||
continue;
|
||||
}
|
||||
sorted.push_back(sym);
|
||||
}
|
||||
|
||||
std::sort(sorted.begin(), sorted.end(), [](asymbol* a, asymbol* b) {
|
||||
auto addra = a->section->vma + a->value;
|
||||
auto addrb = b->section->vma + b->value;
|
||||
if (addra != addrb) return addra < addrb;
|
||||
return strncmp("_ZN4HPHP", a->name, 8) &&
|
||||
!strncmp("_ZN4HPHP", b->name, 8);
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < sorted.size(); i++) {
|
||||
auto sym = sorted[i];
|
||||
auto addr = sym->section->vma + sym->value;
|
||||
unsigned size;
|
||||
if (i + 1 < sorted.size()) {
|
||||
auto s2 = sorted[i + 1];
|
||||
size = s2->section->vma + s2->value - addr;
|
||||
} else {
|
||||
size = uintptr_t(pidMapOverlayEnd) - addr;
|
||||
}
|
||||
if (!size) continue;
|
||||
fprintf(m_perfMap, "%lx %x %s\n",
|
||||
long(addr), size, sym->name);
|
||||
}
|
||||
|
||||
free(symbol_table);
|
||||
free(match);
|
||||
}
|
||||
bfd_close(abfd);
|
||||
return;
|
||||
}
|
||||
|
||||
void DebugInfo::recordStub(TCRange range, const char* name) {
|
||||
if (range.isAstubs()) {
|
||||
m_astubsDwarfInfo.addTracelet(range, name, nullptr, nullptr, false, false);
|
||||
|
||||
@@ -41,8 +41,13 @@ class DebugInfo {
|
||||
|
||||
void debugSync();
|
||||
static DebugInfo* Get();
|
||||
|
||||
static void setPidMapOverlay(void* from, void* to) {
|
||||
pidMapOverlayStart = from;
|
||||
pidMapOverlayEnd = to;
|
||||
}
|
||||
private:
|
||||
void generatePidMapOverlay();
|
||||
|
||||
/* maintain separate dwarf info for a and astubs, so that we
|
||||
* don't emit dwarf info for the two in the same ELF file.
|
||||
* gdb tends to get confused when it sees dwarf info for
|
||||
@@ -56,6 +61,9 @@ class DebugInfo {
|
||||
*/
|
||||
FILE* m_perfMap;
|
||||
char m_perfMapName[64];
|
||||
|
||||
static void* pidMapOverlayStart;
|
||||
static void* pidMapOverlayEnd;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -178,11 +178,19 @@ void forPreorderDoms(Block* block, const DomChildren& children,
|
||||
}
|
||||
}
|
||||
|
||||
template <class Body>
|
||||
void forEachTrace(IRUnit& unit, Body body) {
|
||||
body(unit.main());
|
||||
for (auto& exit : unit.exits()) {
|
||||
body(exit.get());
|
||||
}
|
||||
}
|
||||
|
||||
template <class Body>
|
||||
void forEachTrace(const IRUnit& unit, Body body) {
|
||||
body(unit.main());
|
||||
for (auto exit : unit.exits()) {
|
||||
body(exit);
|
||||
for (auto& exit : unit.exits()) {
|
||||
body(exit.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +199,7 @@ void forEachTraceBlock(const IRUnit& unit, Body body) {
|
||||
for (auto block : unit.main()->blocks()) {
|
||||
body(block);
|
||||
}
|
||||
for (auto exit : unit.exits()) {
|
||||
for (auto& exit : unit.exits()) {
|
||||
for (auto block : exit->blocks()) {
|
||||
body(block);
|
||||
}
|
||||
@@ -208,7 +216,7 @@ void forEachInst(const BlockList& blocks, Body body) {
|
||||
}
|
||||
|
||||
template <class Body>
|
||||
void forEachTraceInst(const IRUnit& unit, Body body) {
|
||||
void forEachTraceInst(IRUnit& unit, Body body) {
|
||||
forEachTrace(unit, [=](IRTrace* t) {
|
||||
forEachInst(t->blocks(), body);
|
||||
});
|
||||
|
||||
@@ -438,9 +438,12 @@ void optimizeActRecs(BlockList& blocks, DceState& state, IRUnit& unit,
|
||||
|
||||
void eliminateDeadCode(IRUnit& unit) {
|
||||
auto removeEmptyExitTraces = [&] {
|
||||
unit.exits().remove_if([](IRTrace* exit) {
|
||||
auto& exits = unit.exits();
|
||||
auto isEmpty = [](smart::unique_ptr<IRTrace>& exit) {
|
||||
return exit->blocks().empty();
|
||||
});
|
||||
};
|
||||
exits.erase(std::remove_if(exits.begin(), exits.end(), isEmpty),
|
||||
exits.end());
|
||||
};
|
||||
|
||||
// kill unreachable code and remove any traces that are now empty
|
||||
|
||||
@@ -69,7 +69,8 @@ bool classIsUniqueInterface(const Class* cls) {
|
||||
HhbcTranslator::HhbcTranslator(Offset startOffset,
|
||||
uint32_t initialSpOffsetFromFp,
|
||||
const Func* func)
|
||||
: m_tb(new TraceBuilder(startOffset,
|
||||
: m_unit(startOffset)
|
||||
, m_tb(new TraceBuilder(startOffset,
|
||||
initialSpOffsetFromFp,
|
||||
m_unit,
|
||||
func))
|
||||
|
||||
@@ -22,6 +22,15 @@ namespace HPHP { namespace JIT {
|
||||
|
||||
TRACE_SET_MOD(hhir);
|
||||
|
||||
IRUnit::IRUnit(Offset initialBcOffset)
|
||||
: m_nextBlockId(0)
|
||||
, m_nextOpndId(0)
|
||||
, m_nextInstId(0)
|
||||
, m_bcOff(initialBcOffset)
|
||||
, m_main(smart::make_unique<IRTrace>(*this, defBlock()))
|
||||
{
|
||||
}
|
||||
|
||||
IRInstruction* IRUnit::defLabel(unsigned numDst, BCMarker marker) {
|
||||
IRInstruction inst(DefLabel, marker);
|
||||
IRInstruction* label = cloneInstruction(&inst);
|
||||
@@ -58,18 +67,10 @@ SSATmp* IRUnit::findConst(ConstData& cdata, Type ctype) {
|
||||
return m_constTable.insert(cloneInstruction(&inst)->dst());
|
||||
}
|
||||
|
||||
Block* IRUnit::makeMain(uint32_t bcOff) {
|
||||
assert(!m_main);
|
||||
auto entry = defBlock();
|
||||
m_bcOff = bcOff;
|
||||
m_main = new (m_arena) IRTrace(*this, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
Block* IRUnit::addExit() {
|
||||
auto exit = defBlock();
|
||||
exit->setHint(Block::Hint::Unlikely);
|
||||
m_exits.push_back(new (m_arena) IRTrace(*this, exit));
|
||||
m_exits.push_back(smart::make_unique<IRTrace>(*this, exit));
|
||||
return exit;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "folly/ScopeGuard.h"
|
||||
#include "hphp/util/arena.h"
|
||||
#include "hphp/runtime/vm/jit/ir.h"
|
||||
#include "hphp/runtime/vm/jit/ir-trace.h"
|
||||
#include "hphp/runtime/vm/jit/cse.h"
|
||||
#include "hphp/runtime/base/memory-manager.h"
|
||||
|
||||
@@ -168,12 +169,7 @@ class IRUnit {
|
||||
TRACE_SET_MOD(hhir);
|
||||
|
||||
public:
|
||||
IRUnit()
|
||||
: m_nextBlockId(0)
|
||||
, m_nextOpndId(0)
|
||||
, m_nextInstId(0)
|
||||
, m_main(nullptr)
|
||||
{}
|
||||
explicit IRUnit(Offset initialBcOffset);
|
||||
|
||||
/*
|
||||
* Create an IRInstruction with lifetime equivalent to this IRUnit.
|
||||
@@ -263,9 +259,8 @@ public:
|
||||
IRInstruction* mov(SSATmp* dst, SSATmp* src, BCMarker marker);
|
||||
|
||||
/*
|
||||
* Create a new trace
|
||||
* Create a new exit trace.
|
||||
*/
|
||||
Block* makeMain(uint32_t bcOff);
|
||||
Block* addExit();
|
||||
|
||||
Arena& arena() { return m_arena; }
|
||||
@@ -273,7 +268,8 @@ public:
|
||||
uint32_t numBlocks() const { return m_nextBlockId; }
|
||||
uint32_t numInsts() const { return m_nextInstId; }
|
||||
CSEHash& constTable() { return m_constTable; }
|
||||
IRTrace* main() const { return m_main; }
|
||||
IRTrace* main() { return m_main.get(); }
|
||||
const IRTrace* main() const { return m_main.get(); }
|
||||
uint32_t bcOff() const { return m_bcOff; }
|
||||
|
||||
// Overloads useful for StateVector and IdSet
|
||||
@@ -281,8 +277,8 @@ public:
|
||||
uint32_t numIds(const Block*) const { return numBlocks(); }
|
||||
uint32_t numIds(const IRInstruction*) const { return numInsts(); }
|
||||
|
||||
typedef std::list<IRTrace*> ExitList;
|
||||
ExitList& exits() { return m_exits; }
|
||||
typedef smart::vector<smart::unique_ptr<IRTrace>> ExitList;
|
||||
ExitList& exits() { return m_exits; }
|
||||
const ExitList& exits() const { return m_exits; }
|
||||
Block* entry() const;
|
||||
std::string toString() const;
|
||||
@@ -296,13 +292,13 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
Arena m_arena; // contains IRTrace, Block, IRInstruction, and SSATmp objects
|
||||
Arena m_arena; // contains Block, IRInstruction, and SSATmp objects
|
||||
CSEHash m_constTable; // DefConst's for each unique constant in this IR
|
||||
uint32_t m_nextBlockId;
|
||||
uint32_t m_nextOpndId;
|
||||
uint32_t m_nextInstId;
|
||||
uint32_t m_bcOff; // bytecode offset where this unit starts
|
||||
IRTrace* m_main; // main entry point trace
|
||||
smart::unique_ptr<IRTrace> m_main; // main entry point trace
|
||||
ExitList m_exits; // exit traces
|
||||
};
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ class NormalizedInstruction {
|
||||
}
|
||||
|
||||
private:
|
||||
smart::vector<smart::unique_ptr<DynLocation>::type> m_dynLocs;
|
||||
smart::vector<smart::unique_ptr<DynLocation>> m_dynLocs;
|
||||
};
|
||||
|
||||
} } // HPHP::Transl
|
||||
|
||||
@@ -353,7 +353,7 @@ static BlockList blocks(const IRUnit& unit,
|
||||
smart::vector<Block*> blocks;
|
||||
blocks.assign(trace->blocks().begin(), trace->blocks().end());
|
||||
if (trace->isMain()) {
|
||||
for (auto exit : unit.exits()) {
|
||||
for (auto& exit : unit.exits()) {
|
||||
blocks.insert(blocks.end(), exit->blocks().begin(), exit->blocks().end());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,11 +454,15 @@ void pmethodCacheMissPath(MethodCache* mce,
|
||||
LeaseHolder writer(Translator::WriteLease());
|
||||
if (!writer) return;
|
||||
|
||||
auto smashMov = [&] (TCA addr, uintptr_t value) {
|
||||
auto smashMov = [&] (TCA addr, uintptr_t value) -> bool {
|
||||
always_assert(isSmashable(addr + 2, 8));
|
||||
assert(addr[0] == 0x49 && addr[1] == 0xba);
|
||||
auto const ptr = reinterpret_cast<uintptr_t*>(addr + 2);
|
||||
if (!(*ptr & 1)) {
|
||||
return false;
|
||||
}
|
||||
*ptr = value;
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -495,12 +499,14 @@ void pmethodCacheMissPath(MethodCache* mce,
|
||||
fval < std::numeric_limits<uint32_t>::max() &&
|
||||
cval < std::numeric_limits<uint32_t>::max();
|
||||
|
||||
uintptr_t imm = 0x2; /* not a Class, but clear low bit */
|
||||
if (cacheable) {
|
||||
assert(!(mce->m_value->attrs() & AttrStatic));
|
||||
auto const imm = fval << 32 | mce->m_key;
|
||||
smashMov(pdata->smashImmAddr, imm);
|
||||
} else {
|
||||
smashMov(pdata->smashImmAddr, 0x2 /* not a Class, but clear low bit */);
|
||||
imm = fval << 32 | cval;
|
||||
}
|
||||
if (!smashMov(pdata->smashImmAddr, imm)) {
|
||||
// someone beat us to it
|
||||
return methodCacheSlowerPath<Fatal>(mce, ar, name, cls);
|
||||
}
|
||||
|
||||
// Regardless of whether the inline cache was populated, smash the
|
||||
|
||||
@@ -35,7 +35,7 @@ TraceBuilder::TraceBuilder(Offset initialBcOffset,
|
||||
: m_unit(unit)
|
||||
, m_simplifier(*this)
|
||||
, m_state(unit, initialSpOffsetFromFp, func)
|
||||
, m_curTrace(m_unit.makeMain(initialBcOffset)->trace())
|
||||
, m_curTrace(m_unit.main())
|
||||
, m_curBlock(nullptr)
|
||||
, m_enableSimplification(false)
|
||||
, m_inReoptimize(false)
|
||||
|
||||
@@ -3170,6 +3170,20 @@ bool shouldAnalyzeCallee(const NormalizedInstruction* fcall,
|
||||
// inline if there are any calls in order to prepare arguments.
|
||||
for (auto* ni = fcall->prev; ni; ni = ni->prev) {
|
||||
if (ni->source.offset() == fpi->m_fpushOff) {
|
||||
if (ni->op() == OpFPushObjMethodD ||
|
||||
ni->op() == OpFPushObjMethod) {
|
||||
if (!ni->inputs[ni->op() == OpFPushObjMethod]->isObject()) {
|
||||
/*
|
||||
* In this case, we're going to throw or fatal when we
|
||||
* execute the FPush*. But we have statically proven that
|
||||
* if we get to the FCall, then target is the Func that will
|
||||
* be called. So the FCall is unreachable - but unfortunately,
|
||||
* various assumptions by the jit will be violated if we try
|
||||
* to inline it. So just don't inline in that case.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (isFCallStar(ni->op()) || ni->op() == OpFCallBuiltin) {
|
||||
|
||||
@@ -1817,11 +1817,11 @@
|
||||
},
|
||||
{
|
||||
"name": "HPHP_VERSION",
|
||||
"value": "2.3.0-dev"
|
||||
"value": "2.3.3"
|
||||
},
|
||||
{
|
||||
"name": "HHVM_VERSION",
|
||||
"value": "2.3.0-dev"
|
||||
"value": "2.3.3"
|
||||
},
|
||||
{
|
||||
"name": "HTML_ENTITIES",
|
||||
|
||||
@@ -1053,6 +1053,9 @@ class Phar extends RecursiveDirectoryIterator
|
||||
if (strpos($filename, $prefix) === 0) {
|
||||
$entry = substr($filename, strlen($prefix) + 1);
|
||||
if (strlen($entry) > 0) {
|
||||
if ($filename[strlen($prefix)] != '/') {
|
||||
continue;
|
||||
}
|
||||
$next_slash = strpos($entry, '/');
|
||||
if ($next_slash !== false) {
|
||||
$entry = substr($entry, 0, $next_slash);
|
||||
|
||||
@@ -388,7 +388,7 @@ bool TestFastCGIServer::VerifyExchange(const TestMessageExchange& mx,
|
||||
printf("Error while receiving payload\n");
|
||||
result = false;
|
||||
} else if (recv_len.toInt32() < len) {
|
||||
printf("Too little date received\n");
|
||||
printf("Too little data received\n");
|
||||
result = false;
|
||||
} else {
|
||||
CHECK(recv_len.toInt32() == len);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
class Hello {
|
||||
public function sayHello($name) {
|
||||
return "Hello $name!";
|
||||
}
|
||||
}
|
||||
|
||||
class StackTest extends PHPUnit_Framework_TestCase {
|
||||
public function testTrueIsActuallyTrue() {
|
||||
$stub = $this->getMock('Hello');
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
$argv[] = __DIR__."/phpunit_mock.inc";
|
||||
$arvc += 1;
|
||||
$_SERVER['argv'] = $argv;
|
||||
$_SERVER['argc'] = $argc;
|
||||
|
||||
include __DIR__."/phpunit.phar";
|
||||
@@ -0,0 +1,7 @@
|
||||
PHPUnit 3.7.22 by Sebastian Bergmann.
|
||||
|
||||
.
|
||||
|
||||
Time: %d second%A, Memory: %s
|
||||
|
||||
OK (1 test, 1 assertion)
|
||||
@@ -0,0 +1,27 @@
|
||||
<?hh ;
|
||||
|
||||
class X {
|
||||
private $foo;
|
||||
|
||||
function __construct($a) {
|
||||
$this->foo = $a;
|
||||
}
|
||||
|
||||
function foo() { return $this->foo; }
|
||||
}
|
||||
|
||||
function foo($q, $a) {
|
||||
$x = getX($q, $a);
|
||||
fiz($x->foo());
|
||||
}
|
||||
|
||||
foo(true, 1);
|
||||
foo(false, "a");
|
||||
|
||||
function fiz($a) {
|
||||
var_dump($a);
|
||||
}
|
||||
function getX($q, $a) {
|
||||
if ($q) $x = new X($a);
|
||||
return $x;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
int(1)
|
||||
HipHop Notice: Undefined variable: x in %s/slow/object_method/bad-inlining.php on line 26
|
||||
HipHop Fatal error: Uncaught exception 'BadMethodCallException' with message 'Call to a member function foo() on a non-object' in %s/slow/object_method/bad-inlining.php:15
|
||||
Stack trace:
|
||||
#0 %s/slow/object_method/bad-inlining.php(19): foo()
|
||||
#1 {main}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
$xml = <<<EOT
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE test [<!ENTITY xxe SYSTEM "XXE_URI">]>
|
||||
<foo>&xxe;</foo>
|
||||
EOT;
|
||||
|
||||
$xml = str_replace('XXE_URI', __DIR__ . '/libxml_disable_entity_loader_payload.txt', $xml);
|
||||
|
||||
function parseXML($xml) {
|
||||
$doc = new DOMDocument();
|
||||
$doc->resolveExternals = true;
|
||||
$doc->substituteEntities = true;
|
||||
$doc->validateOnParse = false;
|
||||
$doc->loadXML($xml, 0);
|
||||
return $doc->saveXML();
|
||||
}
|
||||
|
||||
var_dump(strpos(parseXML($xml), 'SECRET_DATA') !== false);
|
||||
var_dump(libxml_disable_entity_loader(true));
|
||||
var_dump(strpos(parseXML($xml), 'SECRET_DATA') === false);
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
@@ -0,0 +1,7 @@
|
||||
bool(true)
|
||||
bool(false)
|
||||
I/O warning : failed to load external entity "%s"
|
||||
HipHop Warning: %s
|
||||
HipHop Warning: %s
|
||||
bool(true)
|
||||
Done
|
||||
@@ -0,0 +1 @@
|
||||
<?php if (!extension_loaded('simplexml') || !extension_loaded('dom') || defined('PHP_WINDOWS_VERSION_MAJOR')) die('skip'); ?>
|
||||
@@ -0,0 +1 @@
|
||||
SECRET_DATA
|
||||
@@ -491,7 +491,7 @@ std::string Process::GetCPUModel() {
|
||||
do_cpuid(0, regs);
|
||||
|
||||
const int vendor_size = sizeof(regs[1])*3;
|
||||
|
||||
std::swap(regs[2], regs[3]);
|
||||
uint32_t cpu_exthigh = 0;
|
||||
if (memcmp(regs + 1, "GenuineIntel", vendor_size) == 0 ||
|
||||
memcmp(regs + 1, "AuthenticAMD", vendor_size) == 0) {
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
HHVM_VERSION(2.3.0-dev)
|
||||
HHVM_VERSION(2.3.3)
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário