Arquivos
hhvm/hphp/runtime/ext/asio/wait_handle.cpp
T
Mike Magruder f4bed8899a Initialize all fields of Static{Result|Exception}WaitHandle
We force users to use the create() methods of StaticResultWaitHandle and StaticExceptionWaitHandle, which properly set m_resultOrException. However, deserialization will use the normal constructor which was failing to initialize the field. The destructor, then, would operate on random data. This broke hphpd when a stack trace had one of these objects on it somewhere. The 'where' command would succeed, but the next command (which deletes the stack trace), would segfault in the wait handle's destructor.

I think it's fair to not serialize this member. It's not exposed thru PHP except via joining with the wait handle, and I think an argument can be made that it's just plain wrong to join with a deserialized copy of a wait handle. So I've just initialized it to a reasonable default.
2013-07-06 11:12:22 -07:00

107 linhas
3.1 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 1997-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/runtime/ext/ext_asio.h"
#include "hphp/runtime/ext/ext_closure.h"
#include "hphp/runtime/ext/asio/asio_session.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
c_WaitHandle::c_WaitHandle(Class* cb)
: ExtObjectData(cb), m_resultOrException(make_tv<KindOfNull>()) {
}
c_WaitHandle::~c_WaitHandle() {
}
void c_WaitHandle::t___construct() {
throw NotSupportedException(__func__, "WTF? This is an abstract class");
}
void c_WaitHandle::ti_setonjoincallback(CVarRef callback) {
if (!callback.isNull() && !callback.instanceof(c_Closure::s_cls)) {
Object e(SystemLib::AllocInvalidArgumentExceptionObject(
"Unable to set WaitHandle::onJoin: on_join_cb not a closure"));
throw e;
}
AsioSession::Get()->setOnJoinCallback(callback.getObjectDataOrNull());
}
Object c_WaitHandle::t_getwaithandle() {
return this;
}
// throws if cross-context cycle found
void c_WaitHandle::t_import() {
if (isFinished()) {
return;
}
context_idx_t ctx_idx = AsioSession::Get()->getCurrentContextIdx();
if (ctx_idx) {
assert(dynamic_cast<c_WaitableWaitHandle*>(this));
static_cast<c_WaitableWaitHandle*>(this)->enterContext(ctx_idx);
}
}
Variant c_WaitHandle::t_join() {
if (!isFinished()) {
// run the full blown machinery
assert(dynamic_cast<c_WaitableWaitHandle*>(this));
static_cast<c_WaitableWaitHandle*>(this)->join();
}
assert(isFinished());
if (LIKELY(isSucceeded())) {
// succeeded? return result
return tvAsCVarRef(getResult());
} else {
// failed? throw exception
Object e(getException());
throw e;
}
}
bool c_WaitHandle::t_isfinished() {
return isFinished();
}
bool c_WaitHandle::t_issucceeded() {
return isSucceeded();
}
bool c_WaitHandle::t_isfailed() {
return isFailed();
}
int64_t c_WaitHandle::t_getid() {
return ((long) this) / sizeof(void*);
}
String c_WaitHandle::t_getname() {
return getName();
}
Object c_WaitHandle::t_getexceptioniffailed() {
return isFailed() ? getException() : nullptr;
}
///////////////////////////////////////////////////////////////////////////////
}