Skip to content

[ffi] Fix memory leaks #101

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

Merged
merged 1 commit into from
May 3, 2021
Merged
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
6 changes: 6 additions & 0 deletions ffi/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ a.out
sdk-version
*snapshot*
pubspec.lock
CMakeCache.txt
CMakeFiles
cmake_install.cmake
Makefile
primitives/primitives_library/primitives_test
structs/structs_library/structs_test

# Windows
*.obj
Expand Down
18 changes: 15 additions & 3 deletions ffi/primitives/primitives.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ typedef multi_sum_func = Int32 Function(
Int32 numCount, Int32 a, Int32 b, Int32 c);
typedef MultiSum = int Function(int numCount, int a, int b, int c);

// C free function - void free_pointer(int *int_pointer);
//
// Example of how to free pointers that were allocated in C.
typedef free_pointer_func = Void Function(Pointer<Int32> a);
typedef FreePointer = void Function(Pointer<Int32> a);

main() {
// Open the dynamic library
var libraryPath = path.join(
Expand Down Expand Up @@ -64,6 +70,9 @@ main() {
final subtract = subtractPointer.asFunction<Subtract>();
print('3 - 5 = ${subtract(p, 5)}');

// Free up allocated memory.
calloc.free(p);

// calls int *multiply(int a, int b);
final multiplyPointer =
dylib.lookup<NativeFunction<multiply_func>>('multiply');
Expand All @@ -73,13 +82,16 @@ main() {
final int result = resultPointer.value;
print('3 * 5 = $result');

// Free up allocated memory. This time in C, because it was allocated in C.
final freePointerPointer =
dylib.lookup<NativeFunction<free_pointer_func>>('free_pointer');
final freePointer = freePointerPointer.asFunction<FreePointer>();
freePointer(resultPointer);

// example calling a C function with varargs
// calls int multi_sum(int nr_count, ...);
final multiSumPointer =
dylib.lookup<NativeFunction<multi_sum_func>>('multi_sum');
final multiSum = multiSumPointer.asFunction<MultiSum>();
print('3 + 7 + 11 = ${multiSum(3, 3, 7, 11)}');

// Free up allocated memory.
calloc.free(p);
}
7 changes: 7 additions & 0 deletions ffi/primitives/primitives_library/primitives.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,18 @@ int sum(int a, int b)

int *multiply(int a, int b)
{
// Allocates native memory in C.
int *mult = (int *)malloc(sizeof(int));
*mult = a * b;
return mult;
}

void free_pointer(int *int_pointer)
{
// Free native memory in C which was allocated in C.
free(int_pointer);
}

int subtract(int *a, int b)
{
return *a - b;
Expand Down
18 changes: 15 additions & 3 deletions ffi/structs/structs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ typedef reverse_native = Pointer<Utf8> Function(
Pointer<Utf8> str, Int32 length);
typedef Reverse = Pointer<Utf8> Function(Pointer<Utf8> str, int length);

// C function: void free_string(char *str)
typedef free_string_native = Void Function(Pointer<Utf8> str);
typedef FreeString = void Function(Pointer<Utf8> str);

// C function: struct Coordinate create_coordinate(double latitude, double longitude)
typedef create_coordinate_native = Coordinate Function(
Double latitude, Double longitude);
Expand Down Expand Up @@ -64,20 +68,28 @@ main() {

final reverse = dylib.lookupFunction<reverse_native, Reverse>('reverse');
final backwards = 'backwards';
final reversedMessage =
reverse(backwards.toNativeUtf8(), backwards.length).toDartString();
final backwardsUtf8 = backwards.toNativeUtf8();
final reversedMessageUtf8 = reverse(backwardsUtf8, backwards.length);
final reversedMessage = reversedMessageUtf8.toDartString();
calloc.free(backwardsUtf8);
print('$backwards reversed is $reversedMessage');

final freeString =
dylib.lookupFunction<free_string_native, FreeString>('free_string');
freeString(reversedMessageUtf8);

final createCoordinate =
dylib.lookupFunction<create_coordinate_native, CreateCoordinate>(
'create_coordinate');
final coordinate = createCoordinate(3.5, 4.6);
print(
'Coordinate is lat ${coordinate.latitude}, long ${coordinate.longitude}');

final myHomeUtf8 = 'My Home'.toNativeUtf8();
final createPlace =
dylib.lookupFunction<create_place_native, CreatePlace>('create_place');
final place = createPlace('My Home'.toNativeUtf8(), 42.0, 24.0);
final place = createPlace(myHomeUtf8, 42.0, 24.0);
calloc.free(myHomeUtf8);
final name = place.name.toDartString();
final coord = place.coordinate;
print(
Expand Down
7 changes: 7 additions & 0 deletions ffi/structs/structs_library/structs.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ char *hello_world()

char *reverse(char *str, int length)
{
// Allocates native memory in C.
char *reversed_str = (char *)malloc((length + 1) * sizeof(char));
for (int i = 0; i < length; i++)
{
Expand All @@ -37,6 +38,12 @@ char *reverse(char *str, int length)
return reversed_str;
}

void free_string(char *str)
{
// Free native memory in C which was allocated in C.
free(str);
}

struct Coordinate create_coordinate(double latitude, double longitude)
{
struct Coordinate coordinate;
Expand Down