Skip to content

Commit b8ffd62

Browse files
authored
[ffi] Fix memory leaks (#101)
1 parent e71671d commit b8ffd62

File tree

5 files changed

+50
-6
lines changed

5 files changed

+50
-6
lines changed

ffi/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ a.out
66
sdk-version
77
*snapshot*
88
pubspec.lock
9+
CMakeCache.txt
10+
CMakeFiles
11+
cmake_install.cmake
12+
Makefile
13+
primitives/primitives_library/primitives_test
14+
structs/structs_library/structs_test
915

1016
# Windows
1117
*.obj

ffi/primitives/primitives.dart

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ typedef multi_sum_func = Int32 Function(
3535
Int32 numCount, Int32 a, Int32 b, Int32 c);
3636
typedef MultiSum = int Function(int numCount, int a, int b, int c);
3737

38+
// C free function - void free_pointer(int *int_pointer);
39+
//
40+
// Example of how to free pointers that were allocated in C.
41+
typedef free_pointer_func = Void Function(Pointer<Int32> a);
42+
typedef FreePointer = void Function(Pointer<Int32> a);
43+
3844
main() {
3945
// Open the dynamic library
4046
var libraryPath = path.join(
@@ -64,6 +70,9 @@ main() {
6470
final subtract = subtractPointer.asFunction<Subtract>();
6571
print('3 - 5 = ${subtract(p, 5)}');
6672

73+
// Free up allocated memory.
74+
calloc.free(p);
75+
6776
// calls int *multiply(int a, int b);
6877
final multiplyPointer =
6978
dylib.lookup<NativeFunction<multiply_func>>('multiply');
@@ -73,13 +82,16 @@ main() {
7382
final int result = resultPointer.value;
7483
print('3 * 5 = $result');
7584

85+
// Free up allocated memory. This time in C, because it was allocated in C.
86+
final freePointerPointer =
87+
dylib.lookup<NativeFunction<free_pointer_func>>('free_pointer');
88+
final freePointer = freePointerPointer.asFunction<FreePointer>();
89+
freePointer(resultPointer);
90+
7691
// example calling a C function with varargs
7792
// calls int multi_sum(int nr_count, ...);
7893
final multiSumPointer =
7994
dylib.lookup<NativeFunction<multi_sum_func>>('multi_sum');
8095
final multiSum = multiSumPointer.asFunction<MultiSum>();
8196
print('3 + 7 + 11 = ${multiSum(3, 3, 7, 11)}');
82-
83-
// Free up allocated memory.
84-
calloc.free(p);
8597
}

ffi/primitives/primitives_library/primitives.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,18 @@ int sum(int a, int b)
2727

2828
int *multiply(int a, int b)
2929
{
30+
// Allocates native memory in C.
3031
int *mult = (int *)malloc(sizeof(int));
3132
*mult = a * b;
3233
return mult;
3334
}
3435

36+
void free_pointer(int *int_pointer)
37+
{
38+
// Free native memory in C which was allocated in C.
39+
free(int_pointer);
40+
}
41+
3542
int subtract(int *a, int b)
3643
{
3744
return *a - b;

ffi/structs/structs.dart

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ typedef reverse_native = Pointer<Utf8> Function(
3333
Pointer<Utf8> str, Int32 length);
3434
typedef Reverse = Pointer<Utf8> Function(Pointer<Utf8> str, int length);
3535

36+
// C function: void free_string(char *str)
37+
typedef free_string_native = Void Function(Pointer<Utf8> str);
38+
typedef FreeString = void Function(Pointer<Utf8> str);
39+
3640
// C function: struct Coordinate create_coordinate(double latitude, double longitude)
3741
typedef create_coordinate_native = Coordinate Function(
3842
Double latitude, Double longitude);
@@ -64,20 +68,28 @@ main() {
6468

6569
final reverse = dylib.lookupFunction<reverse_native, Reverse>('reverse');
6670
final backwards = 'backwards';
67-
final reversedMessage =
68-
reverse(backwards.toNativeUtf8(), backwards.length).toDartString();
71+
final backwardsUtf8 = backwards.toNativeUtf8();
72+
final reversedMessageUtf8 = reverse(backwardsUtf8, backwards.length);
73+
final reversedMessage = reversedMessageUtf8.toDartString();
74+
calloc.free(backwardsUtf8);
6975
print('$backwards reversed is $reversedMessage');
7076

77+
final freeString =
78+
dylib.lookupFunction<free_string_native, FreeString>('free_string');
79+
freeString(reversedMessageUtf8);
80+
7181
final createCoordinate =
7282
dylib.lookupFunction<create_coordinate_native, CreateCoordinate>(
7383
'create_coordinate');
7484
final coordinate = createCoordinate(3.5, 4.6);
7585
print(
7686
'Coordinate is lat ${coordinate.latitude}, long ${coordinate.longitude}');
7787

88+
final myHomeUtf8 = 'My Home'.toNativeUtf8();
7889
final createPlace =
7990
dylib.lookupFunction<create_place_native, CreatePlace>('create_place');
80-
final place = createPlace('My Home'.toNativeUtf8(), 42.0, 24.0);
91+
final place = createPlace(myHomeUtf8, 42.0, 24.0);
92+
calloc.free(myHomeUtf8);
8193
final name = place.name.toDartString();
8294
final coord = place.coordinate;
8395
print(

ffi/structs/structs_library/structs.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ char *hello_world()
2828

2929
char *reverse(char *str, int length)
3030
{
31+
// Allocates native memory in C.
3132
char *reversed_str = (char *)malloc((length + 1) * sizeof(char));
3233
for (int i = 0; i < length; i++)
3334
{
@@ -37,6 +38,12 @@ char *reverse(char *str, int length)
3738
return reversed_str;
3839
}
3940

41+
void free_string(char *str)
42+
{
43+
// Free native memory in C which was allocated in C.
44+
free(str);
45+
}
46+
4047
struct Coordinate create_coordinate(double latitude, double longitude)
4148
{
4249
struct Coordinate coordinate;

0 commit comments

Comments
 (0)