From 2edd4c3201664f6d904c85545df113593d828777 Mon Sep 17 00:00:00 2001 From: Darin Dimitrov Date: Thu, 8 Apr 2021 14:57:57 +0300 Subject: [PATCH] fix: Blocks memory leak (#100) --- NativeScript/runtime/Interop.h | 4 +++- NativeScript/runtime/Interop.mm | 26 ++++++++++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/NativeScript/runtime/Interop.h b/NativeScript/runtime/Interop.h index bf1863d4..82caa8ca 100644 --- a/NativeScript/runtime/Interop.h +++ b/NativeScript/runtime/Interop.h @@ -126,6 +126,7 @@ class Interop { static id ToObject(v8::Local context, v8::Local arg); static v8::Local GetPrimitiveReturnType(v8::Local context, BinaryTypeEncodingType type, BaseCall* call); private: + static std::pair CreateMethodInternal(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData); static CFTypeRef CreateBlock(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData); template static void SetStructValue(v8::Local value, void* destBuffer, ptrdiff_t position); @@ -186,7 +187,8 @@ class Interop { const void* invoke; JSBlockDescriptor* descriptor; void* userData; - + ffi_closure* ffiClosure; + static JSBlockDescriptor kJSBlockDescriptor; } JSBlock; }; diff --git a/NativeScript/runtime/Interop.mm b/NativeScript/runtime/Interop.mm index e661424f..36b2c0ec 100644 --- a/NativeScript/runtime/Interop.mm +++ b/NativeScript/runtime/Interop.mm @@ -46,43 +46,53 @@ v8::Locker locker(isolate); Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); + BlockWrapper* blockWrapper = static_cast(tns::GetValue(isolate, callback)); tns::DeleteValue(isolate, callback); wrapper->callback_->Reset(); + delete blockWrapper; } } delete wrapper; + ffi_closure_free(block->ffiClosure); block->~JSBlock(); } } }; -IMP Interop::CreateMethod(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData) { +std::pair Interop::CreateMethodInternal(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData) { void* functionPointer; ffi_closure* closure = static_cast(ffi_closure_alloc(sizeof(ffi_closure), &functionPointer)); ParametrizedCall* call = ParametrizedCall::Get(typeEncoding, initialParamIndex, initialParamIndex + argsCount); ffi_status status = ffi_prep_closure_loc(closure, call->Cif, callback, userData, functionPointer); tns::Assert(status == FFI_OK); - return (IMP)functionPointer; + return std::make_pair((IMP)functionPointer, closure); + +} + +IMP Interop::CreateMethod(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData) { + std::pair result = Interop::CreateMethodInternal(initialParamIndex, argsCount, typeEncoding, callback, userData); + return result.first; } CFTypeRef Interop::CreateBlock(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData) { JSBlock* blockPointer = reinterpret_cast(malloc(sizeof(JSBlock))); - void* functionPointer = (void*)CreateMethod(initialParamIndex, argsCount, typeEncoding, callback, userData); + + std::pair result = Interop::CreateMethodInternal(initialParamIndex, argsCount, typeEncoding, callback, userData); *blockPointer = { .isa = nullptr, .flags = JSBlock::BLOCK_HAS_COPY_DISPOSE | JSBlock::BLOCK_NEEDS_FREE | (1 /* ref count */ << 1), .reserved = 0, - .invoke = functionPointer, + .invoke = (void*)result.first, .descriptor = &JSBlock::kJSBlockDescriptor, + .userData = userData, + .ffiClosure = result.second, }; - blockPointer->userData = userData; - object_setClass((__bridge id)blockPointer, objc_getClass("__NSMallocBlock__")); - return blockPointer; + return CFAutorelease(blockPointer); } Local Interop::CallFunction(CMethodCall& methodCall) { @@ -341,7 +351,7 @@ BaseDataWrapper* baseWrapper = tns::GetValue(isolate, arg); if (baseWrapper != nullptr && baseWrapper->Type() == WrapperType::Block) { BlockWrapper* wrapper = static_cast(baseWrapper); - blockPtr = wrapper->Block(); + blockPtr = Block_copy(wrapper->Block()); } else { std::shared_ptr> poCallback = std::make_shared>(isolate, arg); MethodCallbackWrapper* userData = new MethodCallbackWrapper(isolate, poCallback, 1, argsCount, blockTypeEncoding);