Memory Management Improvements #148

Merged
erinn merged 2 commits from memory into trunk 2021-08-25 19:37:17 +00:00
2 changed files with 77 additions and 16 deletions

View File

@ -1 +1 @@
v1.1.0-2021-07-15-19-15 v1.1.1-16-g7376218-2021-08-25-16-54

View File

@ -4,7 +4,6 @@ import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'package:cwtch/cwtch/cwtchNotifier.dart'; import 'package:cwtch/cwtch/cwtchNotifier.dart';
import 'package:flutter/src/services/text_input.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
@ -22,6 +21,9 @@ typedef StartCwtchFn = int Function(Pointer<Utf8> dir, int len, Pointer<Utf8> to
typedef void_from_void_funtion = Void Function(); typedef void_from_void_funtion = Void Function();
typedef VoidFromVoidFunction = void Function(); typedef VoidFromVoidFunction = void Function();
typedef free_function = Void Function(Pointer<Utf8>);
typedef FreeFn = void Function(Pointer<Utf8>);
typedef void_from_string_string_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32); typedef void_from_string_string_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32);
typedef VoidFromStringStringFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int); typedef VoidFromStringStringFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int);
@ -34,25 +36,15 @@ typedef VoidFromStringStringStringStringFn = void Function(Pointer<Utf8>, int, P
typedef void_from_string_string_int_int_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int64, Int64); typedef void_from_string_string_int_int_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int64, Int64);
typedef VoidFromStringStringIntIntFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int, int); typedef VoidFromStringStringIntIntFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int, int);
typedef access_cwtch_eventbus_function = Void Function();
typedef NextEventFn = void Function();
typedef string_to_void_function = Void Function(Pointer<Utf8> str, Int32 length); typedef string_to_void_function = Void Function(Pointer<Utf8> str, Int32 length);
typedef StringFn = void Function(Pointer<Utf8> dir, int); typedef StringFn = void Function(Pointer<Utf8> dir, int);
typedef string_string_to_void_function = Void Function(Pointer<Utf8> str, Int32 length, Pointer<Utf8> str2, Int32 length2); typedef string_string_to_void_function = Void Function(Pointer<Utf8> str, Int32 length, Pointer<Utf8> str2, Int32 length2);
typedef StringStringFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int); typedef StringStringFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int);
typedef get_json_blob_void_function = Pointer<Utf8> Function();
typedef GetJsonBlobVoidFn = Pointer<Utf8> Function();
typedef get_json_blob_string_function = Pointer<Utf8> Function(Pointer<Utf8> str, Int32 length); typedef get_json_blob_string_function = Pointer<Utf8> Function(Pointer<Utf8> str, Int32 length);
typedef GetJsonBlobStringFn = Pointer<Utf8> Function(Pointer<Utf8> str, int len); typedef GetJsonBlobStringFn = Pointer<Utf8> Function(Pointer<Utf8> str, int len);
//func NumMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int) (n C.int) {
typedef get_int_from_str_str_function = Int32 Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32);
typedef GetIntFromStrStrFn = int Function(Pointer<Utf8>, int, Pointer<Utf8>, int);
//func GetMessage(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, message_index C.int) *C.char { //func GetMessage(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, message_index C.int) *C.char {
typedef get_json_blob_from_str_str_int_function = Pointer<Utf8> Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int32); typedef get_json_blob_from_str_str_int_function = Pointer<Utf8> Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int32);
typedef GetJsonBlobFromStrStrIntFn = Pointer<Utf8> Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int); typedef GetJsonBlobFromStrStrIntFn = Pointer<Utf8> Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int);
@ -138,9 +130,7 @@ class CwtchFfi implements Cwtch {
// Called on object being disposed to (presumably on app close) to close the isolate that's listening to libcwtch-go events // Called on object being disposed to (presumably on app close) to close the isolate that's listening to libcwtch-go events
@override @override
void dispose() { void dispose() {
if (cwtchIsolate != null) { cwtchIsolate.kill(priority: Isolate.immediate);
Outdated
Review

why remove? the isolate isn't assigned till Start() so there is a theoretical chance it could be null when called. Also I think we might have put that in when we were covering our asses about trying to gracefully shutdown and putting shutdown calls in multiple places so as to prevent it getting double unallocated and segfaulting on "graceful" exit

why remove? the isolate isn't assigned till Start() so there is a theoretical chance it could be null when called. Also I think we might have put that in when we were covering our asses about trying to gracefully shutdown and putting shutdown calls in multiple places so as to prevent it getting double unallocated and segfaulting on "graceful" exit
Outdated
Review

Flutter linting declares this check as unnecessary. CwtchIsolate can never assigned to null after it is initialized.

Flutter linting declares this check as unnecessary. CwtchIsolate can never assigned to null after it is initialized.
cwtchIsolate.kill(priority: Isolate.immediate);
}
} }
// Entry point for an isolate to listen to a stream of events pulled from libcwtch-go and return them on the sendPort // Entry point for an isolate to listen to a stream of events pulled from libcwtch-go and return them on the sendPort
@ -165,9 +155,21 @@ class CwtchFfi implements Cwtch {
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
final GetAppbusEvent = getAppbusEventC.asFunction<AppbusEventsFn>(); final GetAppbusEvent = getAppbusEventC.asFunction<AppbusEventsFn>();
while (true) { // Embedded Version of _UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved
var free = library.lookup<NativeFunction<free_function>>("c_FreePointer");
final Free = free.asFunction<FreeFn>();
// ignore: non_constant_identifier_names
final GetAppBusEvent = () {
// ignore: non_constant_identifier_names
Pointer<Utf8> result = GetAppbusEvent(); Pointer<Utf8> result = GetAppbusEvent();
String event = result.toDartString(); String event = result.toDartString();
Free(result);
return event;
};
while (true) {
final event = GetAppBusEvent();
if (event.startsWith("{\"EventType\":\"Shutdown\"")) { if (event.startsWith("{\"EventType\":\"Shutdown\"")) {
print("Shutting down isolate thread: $event"); print("Shutting down isolate thread: $event");
@ -184,6 +186,7 @@ class CwtchFfi implements Cwtch {
final SelectProfile = selectProfileC.asFunction<GetJsonBlobStringFn>(); final SelectProfile = selectProfileC.asFunction<GetJsonBlobStringFn>();
final ut8Onion = onion.toNativeUtf8(); final ut8Onion = onion.toNativeUtf8();
SelectProfile(ut8Onion, ut8Onion.length); SelectProfile(ut8Onion, ut8Onion.length);
malloc.free(ut8Onion);
} }
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
@ -194,6 +197,8 @@ class CwtchFfi implements Cwtch {
final utf8nick = nick.toNativeUtf8(); final utf8nick = nick.toNativeUtf8();
final ut8pass = pass.toNativeUtf8(); final ut8pass = pass.toNativeUtf8();
CreateProfile(utf8nick, utf8nick.length, ut8pass, ut8pass.length); CreateProfile(utf8nick, utf8nick.length, ut8pass, ut8pass.length);
malloc.free(utf8nick);
malloc.free(ut8pass);
} }
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
@ -203,6 +208,7 @@ class CwtchFfi implements Cwtch {
final LoadProfiles = loadProfileC.asFunction<StringFn>(); final LoadProfiles = loadProfileC.asFunction<StringFn>();
final ut8pass = pass.toNativeUtf8(); final ut8pass = pass.toNativeUtf8();
LoadProfiles(ut8pass, ut8pass.length); LoadProfiles(ut8pass, ut8pass.length);
malloc.free(ut8pass);
} }
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
@ -214,6 +220,9 @@ class CwtchFfi implements Cwtch {
final utf8handle = handle.toNativeUtf8(); final utf8handle = handle.toNativeUtf8();
Pointer<Utf8> jsonMessageBytes = GetMessage(utf8profile, utf8profile.length, utf8handle, utf8handle.length, index); Pointer<Utf8> jsonMessageBytes = GetMessage(utf8profile, utf8profile.length, utf8handle, utf8handle.length, index);
String jsonMessage = jsonMessageBytes.toDartString(); String jsonMessage = jsonMessageBytes.toDartString();
_UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved(jsonMessageBytes);
malloc.free(utf8profile);
malloc.free(utf8handle);
return jsonMessage; return jsonMessage;
} }
@ -226,6 +235,8 @@ class CwtchFfi implements Cwtch {
final utf8onion = onion.toNativeUtf8(); final utf8onion = onion.toNativeUtf8();
final utf8json = json.toNativeUtf8(); final utf8json = json.toNativeUtf8();
SendAppBusEvent(utf8onion, utf8onion.length, utf8json, utf8json.length); SendAppBusEvent(utf8onion, utf8onion.length, utf8json, utf8json.length);
malloc.free(utf8onion);
malloc.free(utf8json);
} }
@override @override
@ -236,6 +247,7 @@ class CwtchFfi implements Cwtch {
final SendAppBusEvent = sendAppBusEvent.asFunction<StringFn>(); final SendAppBusEvent = sendAppBusEvent.asFunction<StringFn>();
final utf8json = json.toNativeUtf8(); final utf8json = json.toNativeUtf8();
SendAppBusEvent(utf8json, utf8json.length); SendAppBusEvent(utf8json, utf8json.length);
malloc.free(utf8json);
} }
@override @override
@ -247,6 +259,8 @@ class CwtchFfi implements Cwtch {
final u1 = profileOnion.toNativeUtf8(); final u1 = profileOnion.toNativeUtf8();
final u2 = contactHandle.toNativeUtf8(); final u2 = contactHandle.toNativeUtf8();
AcceptContact(u1, u1.length, u2, u2.length); AcceptContact(u1, u1.length, u2, u2.length);
malloc.free(u1);
malloc.free(u2);
} }
@override @override
@ -258,6 +272,8 @@ class CwtchFfi implements Cwtch {
final u1 = profileOnion.toNativeUtf8(); final u1 = profileOnion.toNativeUtf8();
final u2 = contactHandle.toNativeUtf8(); final u2 = contactHandle.toNativeUtf8();
BlockContact(u1, u1.length, u2, u2.length); BlockContact(u1, u1.length, u2, u2.length);
malloc.free(u1);
malloc.free(u2);
} }
@override @override
@ -270,6 +286,9 @@ class CwtchFfi implements Cwtch {
final u2 = contactHandle.toNativeUtf8(); final u2 = contactHandle.toNativeUtf8();
final u3 = message.toNativeUtf8(); final u3 = message.toNativeUtf8();
SendMessage(u1, u1.length, u2, u2.length, u3, u3.length); SendMessage(u1, u1.length, u2, u2.length, u3, u3.length);
malloc.free(u1);
malloc.free(u2);
malloc.free(u3);
} }
@override @override
@ -282,6 +301,9 @@ class CwtchFfi implements Cwtch {
final u2 = contactHandle.toNativeUtf8(); final u2 = contactHandle.toNativeUtf8();
final u3 = target.toNativeUtf8(); final u3 = target.toNativeUtf8();
SendInvitation(u1, u1.length, u2, u2.length, u3, u3.length); SendInvitation(u1, u1.length, u2, u2.length, u3, u3.length);
malloc.free(u1);
malloc.free(u2);
malloc.free(u3);
} }
@override @override
@ -302,6 +324,8 @@ class CwtchFfi implements Cwtch {
final u1 = profileOnion.toNativeUtf8(); final u1 = profileOnion.toNativeUtf8();
final u2 = bundle.toNativeUtf8(); final u2 = bundle.toNativeUtf8();
ImportBundle(u1, u1.length, u2, u2.length); ImportBundle(u1, u1.length, u2, u2.length);
malloc.free(u1);
malloc.free(u2);
} }
@override @override
@ -315,6 +339,10 @@ class CwtchFfi implements Cwtch {
final u3 = key.toNativeUtf8(); final u3 = key.toNativeUtf8();
final u4 = value.toNativeUtf8(); final u4 = value.toNativeUtf8();
SetGroupAttribute(u1, u1.length, u2, u2.length, u3, u3.length, u4, u4.length); SetGroupAttribute(u1, u1.length, u2, u2.length, u3, u3.length, u4, u4.length);
malloc.free(u1);
malloc.free(u2);
malloc.free(u3);
malloc.free(u4);
} }
@override @override
@ -326,9 +354,12 @@ class CwtchFfi implements Cwtch {
final u1 = profileOnion.toNativeUtf8(); final u1 = profileOnion.toNativeUtf8();
final u2 = groupHandle.toNativeUtf8(); final u2 = groupHandle.toNativeUtf8();
RejectInvite(u1, u1.length, u2, u2.length); RejectInvite(u1, u1.length, u2, u2.length);
malloc.free(u1);
malloc.free(u2);
} }
@override @override
// ignore: non_constant_identifier_names
void CreateGroup(String profileOnion, String server, String groupName) { void CreateGroup(String profileOnion, String server, String groupName) {
var createGroup = library.lookup<NativeFunction<void_from_string_string_string_function>>("c_CreateGroup"); var createGroup = library.lookup<NativeFunction<void_from_string_string_string_function>>("c_CreateGroup");
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
@ -337,6 +368,10 @@ class CwtchFfi implements Cwtch {
final u2 = server.toNativeUtf8(); final u2 = server.toNativeUtf8();
final u3 = groupName.toNativeUtf8(); final u3 = groupName.toNativeUtf8();
CreateGroup(u1, u1.length, u2, u2.length, u3, u3.length); CreateGroup(u1, u1.length, u2, u2.length, u3, u3.length);
malloc.free(u1);
malloc.free(u2);
malloc.free(u3);
} }
@override @override
@ -348,6 +383,8 @@ class CwtchFfi implements Cwtch {
final u1 = profileOnion.toNativeUtf8(); final u1 = profileOnion.toNativeUtf8();
final u2 = handle.toNativeUtf8(); final u2 = handle.toNativeUtf8();
LeaveConversation(u1, u1.length, u2, u2.length); LeaveConversation(u1, u1.length, u2, u2.length);
malloc.free(u1);
malloc.free(u2);
} }
@override @override
@ -359,9 +396,12 @@ class CwtchFfi implements Cwtch {
final u1 = profileOnion.toNativeUtf8(); final u1 = profileOnion.toNativeUtf8();
final u2 = groupHandle.toNativeUtf8(); final u2 = groupHandle.toNativeUtf8();
LeaveGroup(u1, u1.length, u2, u2.length); LeaveGroup(u1, u1.length, u2, u2.length);
malloc.free(u1);
malloc.free(u2);
} }
@override @override
// ignore: non_constant_identifier_names
void UpdateMessageFlags(String profile, String handle, int index, int flags) { void UpdateMessageFlags(String profile, String handle, int index, int flags) {
var updateMessageFlagsC = library.lookup<NativeFunction<void_from_string_string_int_int_function>>("c_UpdateMessageFlags"); var updateMessageFlagsC = library.lookup<NativeFunction<void_from_string_string_int_int_function>>("c_UpdateMessageFlags");
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
@ -369,6 +409,8 @@ class CwtchFfi implements Cwtch {
final utf8profile = profile.toNativeUtf8(); final utf8profile = profile.toNativeUtf8();
final utf8handle = handle.toNativeUtf8(); final utf8handle = handle.toNativeUtf8();
updateMessageFlags(utf8profile, utf8profile.length, utf8handle, utf8handle.length, index, flags); updateMessageFlags(utf8profile, utf8profile.length, utf8handle, utf8handle.length, index, flags);
malloc.free(utf8profile);
malloc.free(utf8handle);
} }
@override @override
@ -380,14 +422,18 @@ class CwtchFfi implements Cwtch {
final u1 = onion.toNativeUtf8(); final u1 = onion.toNativeUtf8();
final u2 = currentPassword.toNativeUtf8(); final u2 = currentPassword.toNativeUtf8();
DeleteProfile(u1, u1.length, u2, u2.length); DeleteProfile(u1, u1.length, u2, u2.length);
malloc.free(u1);
malloc.free(u2);
} }
@override @override
// ignore: non_constant_identifier_names
Future<void> Shutdown() async { Future<void> Shutdown() async {
var shutdown = library.lookup<NativeFunction<void_from_void_funtion>>("c_ShutdownCwtch"); var shutdown = library.lookup<NativeFunction<void_from_void_funtion>>("c_ShutdownCwtch");
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
// Shutdown Cwtch + Tor... // Shutdown Cwtch + Tor...
// ignore: non_constant_identifier_names
final Shutdown = shutdown.asFunction<VoidFromVoidFunction>(); final Shutdown = shutdown.asFunction<VoidFromVoidFunction>();
Shutdown(); Shutdown();
@ -400,6 +446,7 @@ class CwtchFfi implements Cwtch {
} }
@override @override
// ignore: non_constant_identifier_names
Future GetMessageByContentHash(String profile, String handle, String contentHash) async { Future GetMessageByContentHash(String profile, String handle, String contentHash) async {
var getMessagesByContentHashC = library.lookup<NativeFunction<get_json_blob_from_str_str_str_function>>("c_GetMessagesByContentHash"); var getMessagesByContentHashC = library.lookup<NativeFunction<get_json_blob_from_str_str_str_function>>("c_GetMessagesByContentHash");
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
@ -409,6 +456,20 @@ class CwtchFfi implements Cwtch {
final utf8contentHash = contentHash.toNativeUtf8(); final utf8contentHash = contentHash.toNativeUtf8();
Pointer<Utf8> jsonMessageBytes = GetMessagesByContentHash(utf8profile, utf8profile.length, utf8handle, utf8handle.length, utf8contentHash, utf8contentHash.length); Pointer<Utf8> jsonMessageBytes = GetMessagesByContentHash(utf8profile, utf8profile.length, utf8handle, utf8handle.length, utf8contentHash, utf8contentHash.length);
String jsonMessage = jsonMessageBytes.toDartString(); String jsonMessage = jsonMessageBytes.toDartString();
_UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved(jsonMessageBytes);
malloc.free(utf8profile);
malloc.free(utf8handle);
malloc.free(utf8contentHash);
return jsonMessage; return jsonMessage;
} }
// ignore: non_constant_identifier_names
// Incredibly dangerous function which invokes a free in libCwtch, should only be used
// as documented in `MEMORY.md` in libCwtch repo.
void _UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved(Pointer<Utf8> ptr) {
Review

LOL

LOL
var free = library.lookup<NativeFunction<free_function>>("c_FreePointer");
final Free = free.asFunction<FreeFn>();
Free(ptr);
}
} }