src: move req_wrap_queue to base class of ReqWrap
Introduce a second base class for `ReqWrap` that does not depend on a template parameter and move the `req_wrap_queue_` field to it. This addresses undefined behaviour that occurs when casting to `ReqWrap<uv_req_t>` in the `ReqWrap` constructor. Refs: https://github.com/nodejs/node/issues/26131 PR-URL: https://github.com/nodejs/node/pull/26148 Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
fab0668123
commit
49a2e40632
@ -420,7 +420,7 @@ void Environment::RegisterHandleCleanups() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Environment::CleanupHandles() {
|
void Environment::CleanupHandles() {
|
||||||
for (ReqWrap<uv_req_t>* request : req_wrap_queue_)
|
for (ReqWrapBase* request : req_wrap_queue_)
|
||||||
request->Cancel();
|
request->Cancel();
|
||||||
|
|
||||||
for (HandleWrap* handle : handle_wrap_queue_)
|
for (HandleWrap* handle : handle_wrap_queue_)
|
||||||
|
@ -873,8 +873,7 @@ class Environment {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef ListHead<HandleWrap, &HandleWrap::handle_wrap_queue_> HandleWrapQueue;
|
typedef ListHead<HandleWrap, &HandleWrap::handle_wrap_queue_> HandleWrapQueue;
|
||||||
typedef ListHead<ReqWrap<uv_req_t>, &ReqWrap<uv_req_t>::req_wrap_queue_>
|
typedef ListHead<ReqWrapBase, &ReqWrapBase::req_wrap_queue_> ReqWrapQueue;
|
||||||
ReqWrapQueue;
|
|
||||||
|
|
||||||
inline HandleWrapQueue* handle_wrap_queue() { return &handle_wrap_queue_; }
|
inline HandleWrapQueue* handle_wrap_queue() { return &handle_wrap_queue_; }
|
||||||
inline ReqWrapQueue* req_wrap_queue() { return &req_wrap_queue_; }
|
inline ReqWrapQueue* req_wrap_queue() { return &req_wrap_queue_; }
|
||||||
|
@ -28,15 +28,14 @@
|
|||||||
V(Environment_HandleWrapQueue, head_, ListNode_HandleWrap, \
|
V(Environment_HandleWrapQueue, head_, ListNode_HandleWrap, \
|
||||||
Environment::HandleWrapQueue::head_) \
|
Environment::HandleWrapQueue::head_) \
|
||||||
V(ListNode_HandleWrap, next_, uintptr_t, ListNode<HandleWrap>::next_) \
|
V(ListNode_HandleWrap, next_, uintptr_t, ListNode<HandleWrap>::next_) \
|
||||||
V(ReqWrap, req_wrap_queue_, ListNode_ReqWrapQueue, \
|
|
||||||
ReqWrap<uv_req_t>::req_wrap_queue_) \
|
|
||||||
V(Environment_ReqWrapQueue, head_, ListNode_ReqWrapQueue, \
|
V(Environment_ReqWrapQueue, head_, ListNode_ReqWrapQueue, \
|
||||||
Environment::ReqWrapQueue::head_) \
|
Environment::ReqWrapQueue::head_) \
|
||||||
V(ListNode_ReqWrap, next_, uintptr_t, ListNode<ReqWrap<uv_req_t>>::next_)
|
V(ListNode_ReqWrap, next_, uintptr_t, ListNode<ReqWrapBase>::next_)
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
int nodedbg_const_ContextEmbedderIndex__kEnvironment__int;
|
int nodedbg_const_ContextEmbedderIndex__kEnvironment__int;
|
||||||
uintptr_t nodedbg_offset_ExternalString__data__uintptr_t;
|
uintptr_t nodedbg_offset_ExternalString__data__uintptr_t;
|
||||||
|
uintptr_t nodedbg_offset_ReqWrap__req_wrap_queue___ListNode_ReqWrapQueue;
|
||||||
|
|
||||||
#define V(Class, Member, Type, Accessor) \
|
#define V(Class, Member, Type, Accessor) \
|
||||||
NODE_EXTERN uintptr_t NODEDBG_OFFSET(Class, Member, Type);
|
NODE_EXTERN uintptr_t NODEDBG_OFFSET(Class, Member, Type);
|
||||||
@ -51,6 +50,9 @@ int GenDebugSymbols() {
|
|||||||
ContextEmbedderIndex::kEnvironment;
|
ContextEmbedderIndex::kEnvironment;
|
||||||
|
|
||||||
nodedbg_offset_ExternalString__data__uintptr_t = NODE_OFF_EXTSTR_DATA;
|
nodedbg_offset_ExternalString__data__uintptr_t = NODE_OFF_EXTSTR_DATA;
|
||||||
|
nodedbg_offset_ReqWrap__req_wrap_queue___ListNode_ReqWrapQueue =
|
||||||
|
OffsetOf<ListNode<ReqWrapBase>, ReqWrap<uv_req_t>>(
|
||||||
|
&ReqWrap<uv_req_t>::req_wrap_queue_);
|
||||||
|
|
||||||
#define V(Class, Member, Type, Accessor) \
|
#define V(Class, Member, Type, Accessor) \
|
||||||
NODEDBG_OFFSET(Class, Member, Type) = OffsetOf(&Accessor);
|
NODEDBG_OFFSET(Class, Member, Type) = OffsetOf(&Accessor);
|
||||||
|
@ -252,7 +252,8 @@ static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
|
|||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
|
||||||
std::vector<Local<Value>> request_v;
|
std::vector<Local<Value>> request_v;
|
||||||
for (auto w : *env->req_wrap_queue()) {
|
for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) {
|
||||||
|
AsyncWrap* w = req_wrap->GetAsyncWrap();
|
||||||
if (w->persistent().IsEmpty())
|
if (w->persistent().IsEmpty())
|
||||||
continue;
|
continue;
|
||||||
request_v.push_back(w->GetOwner());
|
request_v.push_back(w->GetOwner());
|
||||||
|
@ -11,16 +11,16 @@
|
|||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
|
ReqWrapBase::ReqWrapBase(Environment* env) {
|
||||||
|
env->req_wrap_queue()->PushBack(this);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
ReqWrap<T>::ReqWrap(Environment* env,
|
ReqWrap<T>::ReqWrap(Environment* env,
|
||||||
v8::Local<v8::Object> object,
|
v8::Local<v8::Object> object,
|
||||||
AsyncWrap::ProviderType provider)
|
AsyncWrap::ProviderType provider)
|
||||||
: AsyncWrap(env, object, provider) {
|
: AsyncWrap(env, object, provider),
|
||||||
|
ReqWrapBase(env) {
|
||||||
// FIXME(bnoordhuis) The fact that a reinterpret_cast is needed is
|
|
||||||
// arguably a good indicator that there should be more than one queue.
|
|
||||||
env->req_wrap_queue()->PushBack(reinterpret_cast<ReqWrap<uv_req_t>*>(this));
|
|
||||||
|
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +51,11 @@ void ReqWrap<T>::Cancel() {
|
|||||||
uv_cancel(reinterpret_cast<uv_req_t*>(&req_));
|
uv_cancel(reinterpret_cast<uv_req_t*>(&req_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
AsyncWrap* ReqWrap<T>::GetAsyncWrap() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// Below is dark template magic designed to invoke libuv functions that
|
// Below is dark template magic designed to invoke libuv functions that
|
||||||
// initialize uv_req_t instances in a unified fashion, to allow easier
|
// initialize uv_req_t instances in a unified fashion, to allow easier
|
||||||
// tracking of active/inactive requests.
|
// tracking of active/inactive requests.
|
||||||
|
@ -10,8 +10,24 @@
|
|||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
|
class ReqWrapBase {
|
||||||
|
public:
|
||||||
|
explicit inline ReqWrapBase(Environment* env);
|
||||||
|
|
||||||
|
virtual ~ReqWrapBase() {}
|
||||||
|
|
||||||
|
virtual void Cancel() = 0;
|
||||||
|
virtual AsyncWrap* GetAsyncWrap() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend int GenDebugSymbols();
|
||||||
|
friend class Environment;
|
||||||
|
|
||||||
|
ListNode<ReqWrapBase> req_wrap_queue_;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ReqWrap : public AsyncWrap {
|
class ReqWrap : public AsyncWrap, public ReqWrapBase {
|
||||||
public:
|
public:
|
||||||
inline ReqWrap(Environment* env,
|
inline ReqWrap(Environment* env,
|
||||||
v8::Local<v8::Object> object,
|
v8::Local<v8::Object> object,
|
||||||
@ -23,7 +39,8 @@ class ReqWrap : public AsyncWrap {
|
|||||||
// Call this after a request has finished, if re-using this object is planned.
|
// Call this after a request has finished, if re-using this object is planned.
|
||||||
inline void Reset();
|
inline void Reset();
|
||||||
T* req() { return &req_; }
|
T* req() { return &req_; }
|
||||||
inline void Cancel();
|
inline void Cancel() final;
|
||||||
|
inline AsyncWrap* GetAsyncWrap() override;
|
||||||
|
|
||||||
static ReqWrap* from_req(T* req);
|
static ReqWrap* from_req(T* req);
|
||||||
|
|
||||||
@ -31,13 +48,10 @@ class ReqWrap : public AsyncWrap {
|
|||||||
inline int Dispatch(LibuvFunction fn, Args... args);
|
inline int Dispatch(LibuvFunction fn, Args... args);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Environment;
|
|
||||||
friend int GenDebugSymbols();
|
friend int GenDebugSymbols();
|
||||||
template <typename ReqT, typename U>
|
template <typename ReqT, typename U>
|
||||||
friend struct MakeLibuvRequestCallback;
|
friend struct MakeLibuvRequestCallback;
|
||||||
|
|
||||||
ListNode<ReqWrap> req_wrap_queue_;
|
|
||||||
|
|
||||||
typedef void (*callback_t)();
|
typedef void (*callback_t)();
|
||||||
callback_t original_callback_ = nullptr;
|
callback_t original_callback_ = nullptr;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user