From 820aaf5b3d2728d900ba0ff8903d343840766912 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 27 May 2014 23:31:31 +0200 Subject: [PATCH] src: replace CONTAINER_OF with type-safe function Replace the CONTAINER_OF macro with a template function that is as type-safe as a reinterpret_cast<> of an arbitrary pointer can be made. Signed-off-by: Fedor Indutny --- src/cares_wrap.cc | 5 +++-- src/env-inl.h | 8 ++++---- src/node.cc | 4 ++-- src/node_crypto.cc | 16 ++++++---------- src/node_http_parser.cc | 4 ++-- src/node_v8.cc | 2 +- src/node_zlib.cc | 4 ++-- src/signal_wrap.cc | 2 +- src/stream_wrap.cc | 2 +- src/tls_wrap.cc | 4 ++-- src/util-inl.h | 20 ++++++++++++++++++++ src/util.h | 24 +++++++++++++++++------- 12 files changed, 61 insertions(+), 34 deletions(-) diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 0f5987b..f762f2a 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -88,7 +88,7 @@ static void ares_timeout(uv_timer_t* handle) { static void ares_poll_cb(uv_poll_t* watcher, int status, int events) { - ares_task_t* task = CONTAINER_OF(watcher, ares_task_t, poll_watcher); + ares_task_t* task = ContainerOf(&ares_task_t::poll_watcher, watcher); Environment* env = task->env; /* Reset the idle timer */ @@ -109,7 +109,8 @@ static void ares_poll_cb(uv_poll_t* watcher, int status, int events) { static void ares_poll_close_cb(uv_handle_t* watcher) { - ares_task_t* task = CONTAINER_OF(watcher, ares_task_t, poll_watcher); + ares_task_t* task = ContainerOf(&ares_task_t::poll_watcher, + reinterpret_cast(watcher)); free(task); } diff --git a/src/env-inl.h b/src/env-inl.h index 890ddd2..90fc77c 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -276,7 +276,7 @@ inline bool Environment::in_domain() const { inline Environment* Environment::from_immediate_check_handle( uv_check_t* handle) { - return CONTAINER_OF(handle, Environment, immediate_check_handle_); + return ContainerOf(&Environment::immediate_check_handle_, handle); } inline uv_check_t* Environment::immediate_check_handle() { @@ -289,7 +289,7 @@ inline uv_idle_t* Environment::immediate_idle_handle() { inline Environment* Environment::from_idle_prepare_handle( uv_prepare_t* handle) { - return CONTAINER_OF(handle, Environment, idle_prepare_handle_); + return ContainerOf(&Environment::idle_prepare_handle_, handle); } inline uv_prepare_t* Environment::idle_prepare_handle() { @@ -297,7 +297,7 @@ inline uv_prepare_t* Environment::idle_prepare_handle() { } inline Environment* Environment::from_idle_check_handle(uv_check_t* handle) { - return CONTAINER_OF(handle, Environment, idle_check_handle_); + return ContainerOf(&Environment::idle_check_handle_, handle); } inline uv_check_t* Environment::idle_check_handle() { @@ -345,7 +345,7 @@ inline void Environment::set_printed_error(bool value) { } inline Environment* Environment::from_cares_timer_handle(uv_timer_t* handle) { - return CONTAINER_OF(handle, Environment, cares_timer_handle_); + return ContainerOf(&Environment::cares_timer_handle_, handle); } inline uv_timer_t* Environment::cares_timer_handle() { diff --git a/src/node.cc b/src/node.cc index 7a4a090..5d13e8b 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1523,7 +1523,7 @@ static void GetActiveRequests(const FunctionCallbackInfo& args) { int i = 0; QUEUE_FOREACH(q, &req_wrap_queue) { - ReqWrap* w = CONTAINER_OF(q, ReqWrap, req_wrap_queue_); + ReqWrap* w = ContainerOf(&ReqWrap::req_wrap_queue_, q); if (w->persistent().IsEmpty()) continue; ary->Set(i++, w->object()); @@ -1546,7 +1546,7 @@ void GetActiveHandles(const FunctionCallbackInfo& args) { Local owner_sym = env->owner_string(); QUEUE_FOREACH(q, &handle_wrap_queue) { - HandleWrap* w = CONTAINER_OF(q, HandleWrap, handle_wrap_queue_); + HandleWrap* w = ContainerOf(&HandleWrap::handle_wrap_queue_, q); if (w->persistent().IsEmpty() || (w->flags_ & HandleWrap::kUnref)) continue; Local object = w->object(); diff --git a/src/node_crypto.cc b/src/node_crypto.cc index af92870..4201040 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -4027,7 +4027,6 @@ class PBKDF2Request : public AsyncWrap { error_ = err; } - // TODO(trevnorris): Make private and make work with CONTAINER_OF macro. uv_work_t work_req_; private: @@ -4059,7 +4058,7 @@ void EIO_PBKDF2(PBKDF2Request* req) { void EIO_PBKDF2(uv_work_t* work_req) { - PBKDF2Request* req = CONTAINER_OF(work_req, PBKDF2Request, work_req_); + PBKDF2Request* req = ContainerOf(&PBKDF2Request::work_req_, work_req); EIO_PBKDF2(req); } @@ -4078,7 +4077,7 @@ void EIO_PBKDF2After(PBKDF2Request* req, Local argv[2]) { void EIO_PBKDF2After(uv_work_t* work_req, int status) { assert(status == 0); - PBKDF2Request* req = CONTAINER_OF(work_req, PBKDF2Request, work_req_); + PBKDF2Request* req = ContainerOf(&PBKDF2Request::work_req_, work_req); Environment* env = req->env(); HandleScope handle_scope(env->isolate()); Context::Scope context_scope(env->context()); @@ -4257,7 +4256,6 @@ class RandomBytesRequest : public AsyncWrap { error_ = err; } - // TODO(trevnorris): Make private and make work with CONTAINER_OF macro. uv_work_t work_req_; private: @@ -4269,9 +4267,8 @@ class RandomBytesRequest : public AsyncWrap { template void RandomBytesWork(uv_work_t* work_req) { - RandomBytesRequest* req = CONTAINER_OF(work_req, - RandomBytesRequest, - work_req_); + RandomBytesRequest* req = + ContainerOf(&RandomBytesRequest::work_req_, work_req); int r; // Ensure that OpenSSL's PRNG is properly seeded. @@ -4317,9 +4314,8 @@ void RandomBytesCheck(RandomBytesRequest* req, Local argv[2]) { void RandomBytesAfter(uv_work_t* work_req, int status) { assert(status == 0); - RandomBytesRequest* req = CONTAINER_OF(work_req, - RandomBytesRequest, - work_req_); + RandomBytesRequest* req = + ContainerOf(&RandomBytesRequest::work_req_, work_req); Environment* env = req->env(); HandleScope handle_scope(env->isolate()); Context::Scope context_scope(env->context()); diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 3739437..911fec3 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -77,7 +77,7 @@ const uint32_t kOnMessageComplete = 3; #define HTTP_CB(name) \ static int name(http_parser* p_) { \ - Parser* self = CONTAINER_OF(p_, Parser, parser_); \ + Parser* self = ContainerOf(&Parser::parser_, p_); \ return self->name##_(); \ } \ int name##_() @@ -85,7 +85,7 @@ const uint32_t kOnMessageComplete = 3; #define HTTP_DATA_CB(name) \ static int name(http_parser* p_, const char* at, size_t length) { \ - Parser* self = CONTAINER_OF(p_, Parser, parser_); \ + Parser* self = ContainerOf(&Parser::parser_, p_); \ return self->name##_(at, length); \ } \ int name##_(const char* at, size_t length) diff --git a/src/node_v8.cc b/src/node_v8.cc index 6652f61..b71b2a3 100644 --- a/src/node_v8.cc +++ b/src/node_v8.cc @@ -83,7 +83,7 @@ void Environment::IsolateData::AfterGarbageCollection(GCType type, q = QUEUE_HEAD(&queue); QUEUE_REMOVE(q); QUEUE_INSERT_TAIL(&gc_tracker_queue_, q); - Environment* env = CONTAINER_OF(q, Environment, gc_tracker_queue_); + Environment* env = ContainerOf(&Environment::gc_tracker_queue_, q); env->AfterGarbageCollectionCallback(&gc_info_before_, &gc_info_after_); } } diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 4453d82..4f0c938 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -246,7 +246,7 @@ class ZCtx : public AsyncWrap { // for a single write() call, until all of the input bytes have // been consumed. static void Process(uv_work_t* work_req) { - ZCtx *ctx = CONTAINER_OF(work_req, ZCtx, work_req_); + ZCtx *ctx = ContainerOf(&ZCtx::work_req_, work_req); // If the avail_out is left at 0, then it means that it ran out // of room. If there was avail_out left over, then it means @@ -320,7 +320,7 @@ class ZCtx : public AsyncWrap { static void After(uv_work_t* work_req, int status) { assert(status == 0); - ZCtx* ctx = CONTAINER_OF(work_req, ZCtx, work_req_); + ZCtx* ctx = ContainerOf(&ZCtx::work_req_, work_req); Environment* env = ctx->env(); HandleScope handle_scope(env->isolate()); diff --git a/src/signal_wrap.cc b/src/signal_wrap.cc index e1ec2fd..a50340d 100644 --- a/src/signal_wrap.cc +++ b/src/signal_wrap.cc @@ -105,7 +105,7 @@ class SignalWrap : public HandleWrap { } static void OnSignal(uv_signal_t* handle, int signum) { - SignalWrap* wrap = CONTAINER_OF(handle, SignalWrap, handle_); + SignalWrap* wrap = ContainerOf(&SignalWrap::handle_, handle); Environment* env = wrap->env(); HandleScope handle_scope(env->isolate()); Context::Scope context_scope(env->context()); diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index 069d17b..026e204 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -510,7 +510,7 @@ void StreamWrap::SetBlocking(const FunctionCallbackInfo& args) { } void StreamWrap::AfterWrite(uv_write_t* req, int status) { - WriteWrap* req_wrap = CONTAINER_OF(req, WriteWrap, req_); + WriteWrap* req_wrap = ContainerOf(&WriteWrap::req_, req); StreamWrap* wrap = req_wrap->wrap(); Environment* env = wrap->env(); diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index 2f63dfc..b0200a8 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -114,7 +114,7 @@ TLSCallbacks::~TLSCallbacks() { QUEUE* q = QUEUE_HEAD(&pending_write_items_); QUEUE_REMOVE(q); - WriteItem* wi = QUEUE_DATA(q, WriteItem, member_); + WriteItem* wi = ContainerOf(&WriteItem::member_, q); delete wi; } } @@ -145,7 +145,7 @@ bool TLSCallbacks::InvokeQueued(int status) { QUEUE* q = QUEUE_HEAD(&pending_write_items_); QUEUE_REMOVE(q); - WriteItem* wi = QUEUE_DATA(q, WriteItem, member_); + WriteItem* wi = ContainerOf(&WriteItem::member_, q); wi->cb_(&wi->w_->req_, status); delete wi; } diff --git a/src/util-inl.h b/src/util-inl.h index 76015cc..3709208 100644 --- a/src/util-inl.h +++ b/src/util-inl.h @@ -28,6 +28,26 @@ namespace node { +template +ContainerOfHelper::ContainerOfHelper(Inner Outer::*field, + Inner* pointer) + : pointer_(reinterpret_cast( + reinterpret_cast(pointer) - + reinterpret_cast(&(static_cast(0)->*field)))) { +} + +template +template +ContainerOfHelper::operator TypeName*() const { + return static_cast(pointer_); +} + +template +inline ContainerOfHelper ContainerOf(Inner Outer::*field, + Inner* pointer) { + return ContainerOfHelper(field, pointer); +} + template inline v8::Local PersistentToLocal( v8::Isolate* isolate, diff --git a/src/util.h b/src/util.h index 05a7dae..3dcfa55 100644 --- a/src/util.h +++ b/src/util.h @@ -29,13 +29,6 @@ namespace node { -#define OFFSET_OF(TypeName, Field) \ - (reinterpret_cast(&(reinterpret_cast(8)->Field)) - 8) - -#define CONTAINER_OF(Pointer, TypeName, Field) \ - reinterpret_cast( \ - reinterpret_cast(Pointer) - OFFSET_OF(TypeName, Field)) - #define FIXED_ONE_BYTE_STRING(isolate, string) \ (node::OneByteString((isolate), (string), sizeof(string) - 1)) @@ -63,6 +56,23 @@ namespace node { #define UNREACHABLE() abort() +// The helper is for doing safe downcasts from base types to derived types. +template +class ContainerOfHelper { + public: + inline ContainerOfHelper(Inner Outer::*field, Inner* pointer); + template + inline operator TypeName*() const; + private: + Outer* const pointer_; +}; + +// Calculate the address of the outer (i.e. embedding) struct from +// the interior pointer to a data member. +template +inline ContainerOfHelper ContainerOf(Inner Outer::*field, + Inner* pointer); + // If persistent.IsWeak() == false, then do not call persistent.Reset() // while the returned Local is still in scope, it will destroy the // reference to the object. -- 2.7.4