29 Commits

Autor SHA1 Mensagem Data
ptarjan e8141ac49d Revert "Update folly"
This reverts commit 4cf537888b.
2014-01-14 14:50:32 -08:00
Sara Golemon 4cf537888b Update folly
Conflicts:
	CMake/HPHPSetup.cmake
2014-01-14 14:35:31 -08:00
ptarjan 2752b5bbb1 bump version to 2.3.3 2014-01-14 14:21:24 -08:00
Paul Tarjan cc6cbf3852 fix fastcgi segfaults a better way
I think this is what julk originally wanted. He has a `m_keepConn` boolean that is set by `ConnectionFlags::KEEP_CONN` and if that is false, he calls this callback in both the error and the success case.

This doesn't segfault when the connection is abruptly closed by the requestor.

Closes #1522

Reviewed By: @scannell

Differential Revision: D1124995
2014-01-14 14:17:54 -08:00
Antony Puckey 1a4fac8a25 add getRemoteAddr to transport which defaults to empty string. add getRemoteAddr to fastcgi transport to return the proper header. fi no remoteAddr set it to the remoteHost ( libevent ) only set REMOTE_HOST if there is something in it as per php-src
Differential Revision: D1126545
2014-01-14 14:14:39 -08:00
Antony Puckey ae6443500e Set HTTPS header appropriately in fastcgi
Check passed header values for HTTPS.

IIS sets this header to "off" so check for that and empty value before
using transport->setSSL().

Only change to lower case if the value is not empty for performance.

Closes #1546

Reviewed By: @ptarjan

Differential Revision: D1125440

Pulled By: @scannell
2014-01-13 18:37:49 -08:00
Antony Puckey e42452e4f2 Allow transport to override SERVER_ headers
Uses the following headers from the transport (for fastcgi)
instead of the local config if they exist:

SERVER_NAME
SERVER_ADDR
SERVER_PORT

Closes #1445

Reviewed By: @ptarjan

Differential Revision: D1114969

Pulled By: @scannell
2014-01-13 18:37:16 -08:00
Antony Puckey 1dd7e6165e Populate fastcgi (transport-specific) headers
Added new function CopyServerParams in http-protocol which uses the new transport function getServerParams that adds any transport specific SERVER variables ie: FASTCGI_PARAMS to the _SERVER array

Closes #1437
Closes #1511

Reviewed By: @sgolemon

Differential Revision: D1120838

Pulled By: @scannell
2014-01-13 18:36:41 -08:00
Paul Tarjan 01ef59346e Support mod_fastcgi
when using mod_fastcgi SCRIPT_NAME is the Action instead of the actual document you want
this commit uses PATH_TRANSLATED - DOCUMENT_ROOT

tested with:
apache+mod_fastcgi
apache+mod_proxy_fcgi
nginx with no PATH_TRANSLATED header
nginx with this as PATH_TRANSLATED: fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;

Reviewed By: @scannell

Differential Revision: D1114124
2014-01-13 18:36:22 -08:00
Paul Tarjan 9380a44469 delete FastCGIConnection object
This was a leak appearing in @apuckey's valgrind dump. @simpkins said the object should delete itself since either the success or error callbacks will for sure be called for each connection.

Closes #1252

Reviewed By: @scannell

Differential Revision: D1115399
2014-01-13 13:32:58 -08:00
Paul Tarjan 3f859af167 stop emitting regex debugging message
This message is breaking composer installing things with enormous regexes. I tried to change the default error level but @markw65 didn't like that and we need to do something, so I guess lets not emit this if EHHS is off.

Closes #1347

Reviewed By: @markw65

Differential Revision: D1118365
2014-01-13 13:27:01 -08:00
Scott MacVicar 55ecfbdbb6 Fix libxml_disable_entity_loader()
This wasn't calling requestInit and setting the libxml handler no null.
So the first time an error came along it would reset the handler from
no-op to reading again.

This is a much better fix, we set our custom handler in requestInit and
when libxml_disable_entity_loader we store that state as a member bool
ensuring requestInit is always called to set our own handler.

If the handler isn't inserted then the behavious is as before. The only
time this could go pear shaped is say we wanted to make the default be
off. In that case we'd need a global requestInit that is always called
since there are libxml references everywhere.

Reviewed By: @jdelong

Differential Revision: D1116686
2014-01-13 13:20:25 -08:00
ptarjan f951cb8d88 bump version to 2.3.2 2013-12-23 12:51:42 -08:00
Paul Tarjan 2a3225ecd0 fix DOCUMENT_ROOT for fastcgi
We shouldn't have spcialized code in here for fastcgi, and it didn't even work.

Reviewed By: @markw65

Differential Revision: D1109072
2013-12-21 15:36:40 -08:00
Paul Tarjan 65cfdabb76 Allow fastcgi to use the DOCUMENT_ROOT from the web server
: We shouldn't use the current directory or the configured `SourceRoot` since the webserver could have many virtual hosts and always will send us a DOCUMENT_ROOT header.

The only scary part of the change is checking for `sourceRoot` instead of `getDocumentRoot` but I think it is right.

Differential Revision: D1108017
2013-12-21 15:36:27 -08:00
Paul Tarjan 25a26c6bd7 Fix Phar's directory detection
I screwed up the prefix check. Something that is a directory has to have a `/` between the prefix and the file, not just any character.

Closes #1334

Reviewed By: @JoelMarcey

Differential Revision: D1104260
2013-12-20 18:11:39 -08:00
Daniel Sloof 3effbfe5d1 Close pdo connection after request ends
When a request finishes and the PDO connection is not closed in
userland, we need to explictly close it to prevent excessive amount of
connections (and eventually causing MySQL to reject them).

This can obviously be solved in userland by closing the connection in a
register_shutdown_function, but we need to be consistent with PHP.

Closes #1345

Reviewed By: @markw65

Differential Revision: D1098327

Pulled By: @scannell
2013-12-20 11:44:02 -08:00
ptarjan 3a708166b8 bump version to 2.3.1 2013-12-17 13:48:38 -08:00
Paul Tarjan 3c17422435 Make FastCGI less magical for headers
When I changed `getHeaders()` to be the same for fastcgi as all the other transports I didn't notice julk has put in special rules to deal with the fact they weren't the same. Rip that out.

This makes `$_SERVER` contain `HTTP_HOST` instead of just `HOST`.

Reviewed By: @sgolemon

Differential Revision: D1100779
2013-12-17 13:48:08 -08:00
Paul Tarjan d3f23f393f fastcgi headers need unmangling
Headers as mangled in the FastCGI protocol, but the `getHeader()` method on `Transport` assumed the header was the original value.

Closes #1359

Reviewed By: @alexmalyshev

Differential Revision: D1098954
2013-12-17 13:48:07 -08:00
ptarjan 3fa32fab6e bump version for release 2013-12-12 15:23:59 -08:00
mwilliams 075cb79c9f Generate a pid.map file when we unmap parts of the text section
The perf tool won't lookup symbols for parts of the binary
that aren't file mapped, so provide a perf-pid.map file when we
do that.

Reviewed By: @bertmaher

Differential Revision: D1091918
2013-12-12 15:11:25 -08:00
bsimmers a1f2c80031 Don't arena allocate IRTrace
It has a std::list member so we need to run its destructor. I also
cleaned up some type stuff I ran into along the way.

Reviewed By: @jdelong
2013-12-12 15:11:24 -08:00
mwilliams 4e791cc4b6 Fix cpu identification
I broke this when cleaning up some -fstrict-alias warnings.

Reviewed By: @jdelong

Differential Revision: D1087374
2013-12-12 15:11:24 -08:00
mwilliams e62e500a84 Revert "Allow generation of hack types in hhvm thrift extension"
: This reverts commit 6792a3a1a02048f866eeb78937b4c6d5e3b29074.

Reviewed By: @ckwalsh
2013-12-12 15:11:23 -08:00
mwilliams bab7343e83 Fix crash trying to inline after a bad method call
In some cases, we can statically prove that an FCall will
go to a particular method. But that might depend on the fact that
the FPush* would fatal. eg we know that an object is of class Foo,
or is null. The FPushObjMethodD will fatal if its null, so the
FCall is known to call Foo::method (or an override).

But if we try to inline the FCall bad things will happen if the
FPush* was interped. So don't do that.

Reviewed By: @swtaarrs

Differential Revision: D1078789
2013-12-12 15:11:23 -08:00
mwilliams ef3d8e9fc5 Fix crash trying to inline after a bad method call
In some cases, we can statically prove that an FCall will
go to a particular method. But that might depend on the fact that
the FPush* would fatal. eg we know that an object is of class Foo,
or is null. The FPushObjMethodD will fatal if its null, so the
FCall is known to call Foo::method (or an override).

But if we try to inline the FCall bad things will happen if the
FPush* was interped. So don't do that.

Reviewed By: @ottoni
2013-12-12 15:11:22 -08:00
mwilliams 9401291363 Don't translate idx when JitEnableRenameFunctions is set
Users are supposed to be able to override idx with
their own version - but that doesn't work if we translate it
during bytecode emission.

We don't really have a good way of knowing whether its been
overridden, however, so use JitEnableRenameFunctions as we
have for other, similar cases.

Reviewed By: @dariorussi

Differential Revision: D1078332
2013-12-12 15:11:22 -08:00
mwilliams f0665f2e92 Fix race in pmethodCacheMissPath
pmethodCacheMissPath smashes code under the write lease,
but there's nothing to prevent two threads going through it in
sequence - resulting in a double free of the pdata.

Check to see if the code has already been smashed, and bail out if
it has.

Reviewed By: @edwinsmith

Differential Revision: D1078180
2013-12-12 15:10:56 -08:00
54 arquivos alterados com 584 adições e 245 exclusões
+3 -1
Ver Arquivo
@@ -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);
+1 -1
Ver Arquivo
@@ -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))) {
+2 -2
Ver Arquivo
@@ -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 {
+3
Ver Arquivo
@@ -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;
+2
Ver Arquivo
@@ -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
}
+5 -11
Ver Arquivo
@@ -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
-11
Ver Arquivo
@@ -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);
+4 -4
Ver Arquivo
@@ -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());
+15 -10
Ver Arquivo
@@ -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;
}
///////////////////////////////////////////////////////////////////////////////
+6
Ver Arquivo
@@ -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());
+2 -1
Ver Arquivo
@@ -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
+9
Ver Arquivo
@@ -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;
}
+1
Ver Arquivo
@@ -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);
+9 -42
Ver Arquivo
@@ -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;
+8 -52
Ver Arquivo
@@ -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;
}
-2
Ver Arquivo
@@ -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; }
+3 -1
Ver Arquivo
@@ -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) {
+1 -1
Ver Arquivo
@@ -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();
}
+128 -7
Ver Arquivo
@@ -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;
+61 -41
Ver Arquivo
@@ -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();
+3 -2
Ver Arquivo
@@ -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);
+1 -2
Ver Arquivo
@@ -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);
+1 -2
Ver Arquivo
@@ -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()) {
+12 -3
Ver Arquivo
@@ -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;
+1 -1
Ver Arquivo
@@ -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);
+22 -4
Ver Arquivo
@@ -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) {};
/**
+76 -1
Ver Arquivo
@@ -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);
+9 -1
Ver Arquivo
@@ -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;
};
/*
+12 -4
Ver Arquivo
@@ -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);
});
+5 -2
Ver Arquivo
@@ -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
+2 -1
Ver Arquivo
@@ -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))
+10 -9
Ver Arquivo
@@ -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;
}
+9 -13
Ver Arquivo
@@ -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
};
+1 -1
Ver Arquivo
@@ -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
+1 -1
Ver Arquivo
@@ -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());
}
}
+11 -5
Ver Arquivo
@@ -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
+1 -1
Ver Arquivo
@@ -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)
+14
Ver Arquivo
@@ -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) {
+2 -2
Ver Arquivo
@@ -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",
+3
Ver Arquivo
@@ -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);
+1 -1
Ver Arquivo
@@ -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);
+14
Ver Arquivo
@@ -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);
}
}
+8
Ver Arquivo
@@ -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
+1 -1
Ver Arquivo
@@ -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
Ver Arquivo
@@ -1 +1 @@
HHVM_VERSION(2.3.0-dev)
HHVM_VERSION(2.3.3)