From ba73b8882ddbcdcb6fd4bf07dfe29929a2989099 Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Wed, 23 Jan 2019 12:59:51 +0100 Subject: [PATCH] UniquePersistent all over, app.forcefully_free --- examples/GracefulShutdown.js | 6 +++++ src/AppWrapper.h | 45 +++++++++++++++++++++--------------- uWebSockets | 2 +- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/examples/GracefulShutdown.js b/examples/GracefulShutdown.js index 10c3e4d..be14bb3 100644 --- a/examples/GracefulShutdown.js +++ b/examples/GracefulShutdown.js @@ -37,3 +37,9 @@ const app = uWS./*SSL*/App({ console.log('Failed to listen to port ' + port); } }); + +/* This is questionable */ +process.on('beforeExit', () => { + console.log('Forcefully freeing app now'); + app.forcefully_free(); +}); diff --git a/src/AppWrapper.h b/src/AppWrapper.h index f3ba3e8..8cc58e5 100644 --- a/src/AppWrapper.h +++ b/src/AppWrapper.h @@ -14,12 +14,10 @@ void uWS_App_ws(const FunctionCallbackInfo &args) { return; } - /* We don't need to care for these just yet, since we do - * not have a way to free the app itself */ - Persistent *openPf = new Persistent(); - Persistent *messagePf = new Persistent(); - Persistent *drainPf = new Persistent(); - Persistent *closePf = new Persistent(); + UniquePersistent openPf; + UniquePersistent messagePf; + UniquePersistent drainPf; + UniquePersistent closePf; struct PerSocketData { Persistent *socketPf; @@ -46,16 +44,16 @@ void uWS_App_ws(const FunctionCallbackInfo &args) { } /* Open */ - openPf->Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "open")))); + openPf.Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "open")))); /* Message */ - messagePf->Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "message")))); + messagePf.Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "message")))); /* Drain */ - drainPf->Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "drain")))); + drainPf.Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "drain")))); /* Close */ - closePf->Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "close")))); + closePf.Reset(args.GetIsolate(), Local::Cast(behaviorObject->Get(String::NewFromUtf8(isolate, "close")))); } - behavior.open = [openPf](auto *ws, auto *req) { + behavior.open = [openPf = std::move(openPf)](auto *ws, auto *req) { HandleScope hs(isolate); /* Create a new websocket object */ @@ -72,10 +70,10 @@ void uWS_App_ws(const FunctionCallbackInfo &args) { perSocketData->socketPf->Reset(isolate, wsObject); Local argv[] = {wsObject, reqObject}; - Local::New(isolate, *openPf)->Call(isolate->GetCurrentContext()->Global(), 2, argv); + Local::New(isolate, openPf)->Call(isolate->GetCurrentContext()->Global(), 2, argv); }; - behavior.message = [messagePf](auto *ws, std::string_view message, uWS::OpCode opCode) { + behavior.message = [messagePf = std::move(messagePf)](auto *ws, std::string_view message, uWS::OpCode opCode) { HandleScope hs(isolate); Local messageArrayBuffer = ArrayBuffer::New(isolate, (void *) message.data(), message.length()); @@ -84,19 +82,19 @@ void uWS_App_ws(const FunctionCallbackInfo &args) { Local argv[3] = {Local::New(isolate, *(perSocketData->socketPf)), messageArrayBuffer, Boolean::New(isolate, opCode == uWS::OpCode::BINARY)}; - Local::New(isolate, *messagePf)->Call(isolate->GetCurrentContext()->Global(), 3, argv); + Local::New(isolate, messagePf)->Call(isolate->GetCurrentContext()->Global(), 3, argv); /* Important: we clear the ArrayBuffer to make sure it is not invalidly used after return */ messageArrayBuffer->Neuter(); }; - behavior.drain = [drainPf](auto *ws) { + behavior.drain = [drainPf = std::move(drainPf)](auto *ws) { HandleScope hs(isolate); PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); Local argv[1] = {Local::New(isolate, *(perSocketData->socketPf)) }; - Local::New(isolate, *drainPf)->Call(isolate->GetCurrentContext()->Global(), 1, argv); + Local::New(isolate, drainPf)->Call(isolate->GetCurrentContext()->Global(), 1, argv); }; behavior.ping = [](auto *ws) { @@ -107,7 +105,7 @@ void uWS_App_ws(const FunctionCallbackInfo &args) { }; - behavior.close = [closePf](auto *ws, int code, std::string_view message) { + behavior.close = [closePf = std::move(closePf)](auto *ws, int code, std::string_view message) { HandleScope hs(isolate); Local messageArrayBuffer = ArrayBuffer::New(isolate, (void *) message.data(), message.length()); @@ -119,7 +117,7 @@ void uWS_App_ws(const FunctionCallbackInfo &args) { /* Invalidate this wsObject */ wsObject->SetAlignedPointerInInternalField(0, nullptr); - Local::New(isolate, *closePf)->Call(isolate->GetCurrentContext()->Global(), 3, argv); + Local::New(isolate, closePf)->Call(isolate->GetCurrentContext()->Global(), 3, argv); delete perSocketData->socketPf; @@ -184,6 +182,14 @@ void uWS_App_listen(const FunctionCallbackInfo &args) { args.GetReturnValue().Set(args.Holder()); } +/* Mostly indended for debugging memory leaks */ +template +void uWS_App_forcefully_free(const FunctionCallbackInfo &args) { + APP *app = (APP *) args.Holder()->GetAlignedPointerFromInternalField(0); + + delete app; +} + template void uWS_App(const FunctionCallbackInfo &args) { Local appTemplate = FunctionTemplate::New(isolate); @@ -299,6 +305,9 @@ void uWS_App(const FunctionCallbackInfo &args) { appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "ws"), FunctionTemplate::New(isolate, uWS_App_ws)); appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "listen"), FunctionTemplate::New(isolate, uWS_App_listen)); + /* forcefully_free is unsafe for end-users to use, but nice to track memory leaks with ASAN */ + appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "forcefully_free"), FunctionTemplate::New(isolate, uWS_App_forcefully_free)); + Local localApp = appTemplate->GetFunction()->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); localApp->SetAlignedPointerInInternalField(0, app); diff --git a/uWebSockets b/uWebSockets index 9829f7f..e653e9d 160000 --- a/uWebSockets +++ b/uWebSockets @@ -1 +1 @@ -Subproject commit 9829f7fb37c129ac4945cfd58355959270d73d8f +Subproject commit e653e9d3142f8a9a9d76548e288652ab46729766