17 Commits

Autor SHA1 Mensagem Data
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
46 arquivos alterados com 372 adições e 215 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 {
+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());
+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; }
@@ -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,8 @@
#include "hphp/util/timer.h"
#include "folly/MoveWrapper.h"
#include <boost/algorithm/string/predicate.hpp>
using folly::IOBuf;
using folly::IOBufQueue;
using folly::io::Cursor;
@@ -47,6 +50,10 @@ 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();
}
@@ -127,7 +134,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,7 +184,12 @@ 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::addHeaderImpl(const char *name, const char *value) {
@@ -225,6 +278,7 @@ 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";
void FastCGITransport::onHeader(std::unique_ptr<folly::IOBuf> key_chain,
std::unique_ptr<folly::IOBuf> value_chain) {
@@ -288,12 +342,14 @@ 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");
m_serverObject = getRawHeader("SCRIPT_NAME");
std::string queryString = getRawHeader("QUERY_STRING");
if (!queryString.empty()) {
m_serverObject += "?" + queryString;
}
@@ -49,6 +49,7 @@ public:
virtual const char *getUrl() override;
virtual const char *getRemoteHost() override;
virtual uint16_t getRemotePort() override;
virtual const std::string getDocumentRoot() override;
virtual const void *getPostData(int &size) override;
virtual bool hasMorePostData() override;
@@ -87,6 +88,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);
@@ -101,6 +111,7 @@ private:
static const std::string k_methodKey;
static const std::string k_httpVersionKey;
static const std::string k_contentLengthKey;
static const std::string k_documentRoot;
FastCGIConnection* m_connection;
int m_id;
@@ -108,6 +119,7 @@ private:
std::unique_ptr<folly::IOBuf> m_currBody;
HeaderMap m_requestHeaders;
std::string m_requestURI;
std::string m_documentRoot;
std::string m_remoteHost;
uint16_t m_remotePort;
Method m_method;
+10 -31
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;
@@ -515,15 +500,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 +573,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);
+1 -2
Ver Arquivo
@@ -59,8 +59,7 @@ public:
const SourceRootInfo &sri,
const VirtualHost *vhost);
static void CopyHeaderVariables(Variant& server,
const HeaderMap& headers,
bool normalize);
const HeaderMap& headers);
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);
+2
Ver Arquivo
@@ -109,6 +109,8 @@ public:
virtual const char *getUrl() = 0;
virtual const char *getRemoteHost() = 0;
virtual uint16_t getRemotePort() = 0;
// The transport can override the virtualhosts' docroot
virtual const std::string getDocumentRoot() { return ""; }
/**
* POST request's data.
+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.2"
},
{
"name": "HHVM_VERSION",
"value": "2.3.0-dev"
"value": "2.3.2"
},
{
"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}
+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.2)