Skip to content

fix: Blocks memory leak (#100) #110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion NativeScript/runtime/Interop.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class Interop {
static id ToObject(v8::Local<v8::Context> context, v8::Local<v8::Value> arg);
static v8::Local<v8::Value> GetPrimitiveReturnType(v8::Local<v8::Context> context, BinaryTypeEncodingType type, BaseCall* call);
private:
static std::pair<IMP, ffi_closure*> 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 <typename T>
static void SetStructValue(v8::Local<v8::Value> value, void* destBuffer, ptrdiff_t position);
Expand Down Expand Up @@ -186,7 +187,8 @@ class Interop {
const void* invoke;
JSBlockDescriptor* descriptor;
void* userData;

ffi_closure* ffiClosure;

static JSBlockDescriptor kJSBlockDescriptor;
} JSBlock;
};
Expand Down
26 changes: 18 additions & 8 deletions NativeScript/runtime/Interop.mm
Original file line number Diff line number Diff line change
Expand Up @@ -46,43 +46,53 @@
v8::Locker locker(isolate);
Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);
BlockWrapper* blockWrapper = static_cast<BlockWrapper*>(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<IMP, ffi_closure*> 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*>(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<IMP, ffi_closure*> 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<JSBlock*>(malloc(sizeof(JSBlock)));
void* functionPointer = (void*)CreateMethod(initialParamIndex, argsCount, typeEncoding, callback, userData);

std::pair<IMP, ffi_closure*> 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<Value> Interop::CallFunction(CMethodCall& methodCall) {
Expand Down Expand Up @@ -341,7 +351,7 @@
BaseDataWrapper* baseWrapper = tns::GetValue(isolate, arg);
if (baseWrapper != nullptr && baseWrapper->Type() == WrapperType::Block) {
BlockWrapper* wrapper = static_cast<BlockWrapper*>(baseWrapper);
blockPtr = wrapper->Block();
blockPtr = Block_copy(wrapper->Block());
} else {
std::shared_ptr<Persistent<Value>> poCallback = std::make_shared<Persistent<Value>>(isolate, arg);
MethodCallbackWrapper* userData = new MethodCallbackWrapper(isolate, poCallback, 1, argsCount, blockTypeEncoding);
Expand Down