Skip to content

Commit f2aa176

Browse files
committed
fix: memory issue for type encoding
1 parent 081bbcb commit f2aa176

File tree

10 files changed

+90
-55
lines changed

10 files changed

+90
-55
lines changed

dart_native/ios/Classes/DNBlockWrapper.m

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,9 @@ - (void)dealloc {
148148
ffi_closure_free(_closure);
149149
free(_descriptor);
150150
for (int i = 0; i < _numberOfArguments; i++) {
151-
free((void *)_typeEncodings[i]);
151+
if (*_typeEncodings[i] == '{') {
152+
free((void *)_typeEncodings[i]);
153+
}
152154
}
153155
free(_typeEncodings);
154156
NotifyDeallocToDart(_sequence, _dartPort);
@@ -280,16 +282,7 @@ - (NSString *)_parseTypeNames:(NSString *)typeNames
280282
}
281283
}
282284

283-
const char *encodeSource = encode.UTF8String;
284-
size_t typeLength = strlen(encodeSource) + 1;
285-
size_t size = sizeof(char) * typeLength;
286-
char *typePtr = (char *)malloc(size);
287-
if (typePtr == NULL) {
288-
DN_ERROR(DNCreateTypeEncodingError, @"malloc for type encoding fail: %s", encodeSource);
289-
return nil;
290-
}
291-
strlcpy(typePtr, encode.UTF8String, typeLength);
292-
self.typeEncodings[i] = typePtr;
285+
self.typeEncodings[i] = native_type_encoding(encode.UTF8String);
293286

294287
int length = DNTypeLengthWithTypeName(typeStr);
295288

dart_native/ios/Classes/DNMethodIMP.m

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ static void DNFFIIMPClosureFunc(ffi_cif *cif, void *ret, void **args, void *user
167167
args[i + indexOffset] = temp;
168168
}
169169
}
170-
171-
const char **types = native_types_encoding(methodIMP.typeEncoding, NULL, 0);
170+
int typesCount = 0;
171+
const char **types = native_types_encoding(methodIMP.typeEncoding, &typesCount, 0);
172172
if (!types) {
173173
return;
174174
}
@@ -190,6 +190,11 @@ static void DNFFIIMPClosureFunc(ffi_cif *cif, void *ret, void **args, void *user
190190
[invocation retainArguments];
191191
NotifyMethodPerformToDart(invocation, methodIMP, numberOfArguments, types);
192192
}
193+
for (int i = 0; i < typesCount; i++) {
194+
if (*types[i] == '{') {
195+
free((void *)types[i]);
196+
}
197+
}
193198
free(types);
194199
retObjectAddr = (int64_t)*(void **)retAddr;
195200
DNHandleReturnValue(ret, methodIMP, invocation);

dart_native/ios/Classes/native_runtime.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ DN_EXTERN NSMethodSignature * _Nullable
2222
native_method_signature(Class cls, SEL selector);
2323

2424
DN_EXTERN void
25-
native_signature_encoding_list(NSMethodSignature *signature, const char * _Nonnull * _Nonnull typeEncodings);
25+
native_signature_encoding_list(NSMethodSignature *signature, const char * _Nonnull * _Nonnull typeEncodings, BOOL decodeRetVal);
2626

2727
DN_EXTERN BOOL
2828
native_add_method(id target, SEL selector, char *types, void *callback, Dart_Port dartPort);

dart_native/ios/Classes/native_runtime.mm

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,18 @@
3232
}
3333

3434
void
35-
native_signature_encoding_list(NSMethodSignature *signature, const char **typeEncodings) {
35+
native_signature_encoding_list(NSMethodSignature *signature, const char **typeEncodings, BOOL decodeRetVal) {
3636
if (!signature || !typeEncodings) {
3737
return;
3838
}
3939

4040
for (NSUInteger i = 2; i < signature.numberOfArguments; i++) {
41-
*(typeEncodings + i - 1) = [signature getArgumentTypeAtIndex:i];
41+
const char *type = [signature getArgumentTypeAtIndex:i];
42+
*(typeEncodings + i - 1) = native_type_encoding(type);
43+
}
44+
if (decodeRetVal) {
45+
*typeEncodings = native_type_encoding(signature.methodReturnType);
4246
}
43-
*typeEncodings = signature.methodReturnType;
4447
}
4548

4649
BOOL
@@ -281,6 +284,7 @@
281284

282285
#define PTR(type) COND(type, typeList[16])
283286

287+
// When returns struct encoding, it needs to be freed.
284288
const char *
285289
native_type_encoding(const char *str) {
286290
if (!str || strlen(str) == 0) {
@@ -329,7 +333,7 @@
329333
return str;
330334
}
331335

332-
// Returns type encodings whose need be freed.
336+
// Returns type encodings whose need to be freed.
333337
const char **
334338
native_types_encoding(const char *str, int *count, int startIndex) {
335339
int argCount = DNTypeCount(str) - startIndex;
@@ -365,6 +369,7 @@
365369
return argTypes;
366370
}
367371

372+
// Returns struct encoding which will be freed.
368373
const char *
369374
native_struct_encoding(const char *encoding) {
370375
NSUInteger size, align;
@@ -392,7 +397,12 @@
392397
}
393398
[structType appendString:@"}"];
394399
free(elements);
395-
return structType.UTF8String;
400+
// Malloc struct type, it will be freed on dart side.
401+
const char *encodeSource = structType.UTF8String;
402+
size_t typeLength = strlen(encodeSource) + 1;
403+
char *typePtr = (char *)malloc(sizeof(char) * typeLength);
404+
strlcpy(typePtr, encodeSource, typeLength);
405+
return typePtr;
396406
}
397407

398408
bool
-24 Bytes
Binary file not shown.

dart_native/lib/src/ios/common/callback_register.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ _callback(
5555
// types: ret, self, _cmd, args...
5656
Pointer<Utf8> argTypePtr = typesPtrPtr.elementAt(i + 3).value;
5757
Pointer<Void> ptr = argsPtrPtrPtr.elementAt(i + argStartIndex).value.cast();
58-
if (argTypePtr.encodingForStruct == null) {
58+
if (!argTypePtr.isStruct) {
5959
ptr = ptr.cast<Pointer<Void>>().value;
6060
}
6161
dynamic arg = loadValueFromPointer(ptr, argTypePtr);

dart_native/lib/src/ios/common/pointer_encoding.dart

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ extension TypeEncodings on Pointer<Utf8> {
3333

3434
// Return encoding only if type is struct.
3535
String get encodingForStruct {
36-
String result = Utf8.fromUtf8(this);
37-
if (result.startsWith('{')) {
38-
return result;
36+
if (isStruct) {
37+
return Utf8.fromUtf8(this);
3938
}
4039
return null;
4140
}
4241

42+
bool get isStruct {
43+
// ascii for '{' is 123.
44+
return cast<Uint8>().value == 123;
45+
}
46+
4347
bool get isNum {
4448
bool result = this == TypeEncodings.sint8 ||
4549
this == TypeEncodings.sint16 ||
@@ -169,7 +173,7 @@ dynamic storeValueToPointer(
169173
} else if (object is Pointer && encoding.maybeCString) {
170174
Pointer<Void> tempPtr = object.cast<Void>();
171175
ptr.value = tempPtr;
172-
} else if (encoding.encodingForStruct != null) {
176+
} else if (encoding.isStruct) {
173177
// ptr is struct pointer
174178
return storeStructToPointer(ptr, object);
175179
} else {
@@ -262,6 +266,9 @@ Map<Pointer<Utf8>, Function> _loadValueStrategyMap = {
262266
Pointer<Utf8> temp = ptr.cast();
263267
return Utf8.fromUtf8(temp);
264268
},
269+
// TypeEncodings.pointer: (Pointer<Void> ptr) {
270+
// return ptr;
271+
// },
265272
TypeEncodings.v: (Pointer<Void> ptr) {
266273
return;
267274
},
@@ -290,13 +297,12 @@ dynamic loadValueFromPointer(Pointer<Void> ptr, Pointer<Utf8> encoding) {
290297
if (ptr == nullptr) {
291298
return null;
292299
}
293-
// built-in struct.
294-
String structEncoding = encoding.encodingForStruct;
295-
if (structEncoding == null) {
296-
result = ptr;
300+
// built-in struct, [ptr] is struct pointer.
301+
var struct = loadStructFromPointer(ptr, encoding.encodingForStruct);
302+
if (struct != null) {
303+
result = struct;
297304
} else {
298-
// ptr is struct pointer
299-
result = loadStructFromPointer(ptr, structEncoding);
305+
result = ptr;
300306
}
301307
}
302308
}
@@ -316,9 +322,12 @@ String structNameForEncoding(String encoding) {
316322
}
317323

318324
NativeStruct loadStructFromPointer(Pointer<Void> ptr, String encoding) {
319-
NativeStruct result;
325+
if (encoding == null) {
326+
return null;
327+
}
320328
String structName = structNameForEncoding(encoding);
321329
if (structName != null) {
330+
NativeStruct result;
322331
// struct
323332
switch (structName) {
324333
case 'CGSize':
@@ -350,8 +359,11 @@ NativeStruct loadStructFromPointer(Pointer<Void> ptr, String encoding) {
350359
break;
351360
default:
352361
}
362+
if (result != null) {
363+
return result..wrapper;
364+
}
353365
}
354-
return result..wrapper;
366+
return null;
355367
}
356368

357369
Map<String, String> _nativeTypeNameMap = {

dart_native/lib/src/ios/runtime/block.dart

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class Block extends id {
139139
}
140140
int stringTypeBitmask = 0;
141141
Pointer<Pointer<Void>> argsPtrPtr = nullptr.cast();
142+
List<Pointer<Utf8>> structTypes = [];
142143
if (args != null) {
143144
argsPtrPtr = allocate<Pointer<Void>>(count: args.length);
144145
for (var i = 0; i < args.length; i++) {
@@ -149,17 +150,25 @@ class Block extends id {
149150
if (arg is String) {
150151
stringTypeBitmask |= (0x1 << i);
151152
}
152-
storeValueToPointer(
153-
arg, argsPtrPtr.elementAt(i), typesPtrPtr.elementAt(i + 2).value);
153+
var argTypePtr = typesPtrPtr.elementAt(i + 2).value;
154+
if (argTypePtr.isStruct) {
155+
structTypes.add(argTypePtr);
156+
}
157+
storeValueToPointer(arg, argsPtrPtr.elementAt(i), argTypePtr);
154158
}
155159
}
156160
Pointer<Void> resultPtr =
157161
blockInvoke(pointer, argsPtrPtr, nativePort, stringTypeBitmask);
158162
if (argsPtrPtr != nullptr.cast()) {
159163
free(argsPtrPtr);
160164
}
161-
dynamic result =
162-
loadValueFromPointer(resultPtr, typesPtrPtr.elementAt(0).value);
165+
var retTypePtr = typesPtrPtr.elementAt(0).value;
166+
if (retTypePtr.isStruct) {
167+
structTypes.add(retTypePtr);
168+
}
169+
dynamic result = loadValueFromPointer(resultPtr, retTypePtr);
170+
// free struct type memory (malloc on native side)
171+
structTypes.forEach(free);
163172
return result;
164173
}
165174
}
@@ -181,10 +190,9 @@ _callback(Pointer<Pointer<Pointer<Void>>> argsPtrPtrPtr,
181190
Pointer<Pointer<Utf8>> typesPtrPtr = pointer.cast();
182191
for (var i = 0; i < argCount; i++) {
183192
// Get block args encoding. First is return type.
184-
Pointer<Utf8> argTypePtr =
185-
nativeTypeEncoding(typesPtrPtr.elementAt(i + 1).value);
193+
Pointer<Utf8> argTypePtr = typesPtrPtr.elementAt(i + 1).value;
186194
Pointer<Void> ptr = argsPtrPtrPtr.elementAt(i + argStartIndex).value.cast();
187-
if (argTypePtr.encodingForStruct == null) {
195+
if (!argTypePtr.isStruct) {
188196
ptr = ptr.cast<Pointer<Void>>().value;
189197
}
190198
dynamic arg = loadValueFromPointer(ptr, argTypePtr);
@@ -199,8 +207,7 @@ _callback(Pointer<Pointer<Pointer<Void>>> argsPtrPtrPtr,
199207
dynamic result = Function.apply(block.function, args);
200208

201209
if (result != null) {
202-
Pointer<Utf8> resultTypePtr =
203-
nativeTypeEncoding(typesPtrPtr.elementAt(0).value);
210+
Pointer<Utf8> resultTypePtr = typesPtrPtr.elementAt(0).value;
204211
Pointer<Pointer<Void>> realRetPtrPtr = retPtrPtr;
205212
if (stret) {
206213
realRetPtrPtr = argsPtrPtrPtr.elementAt(0).value;

dart_native/lib/src/ios/runtime/internal/native_runtime.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ final MethodSignature nativeMethodSignature =
99
runtimeLib.lookupFunction<MethodSignature, MethodSignature>(
1010
'native_method_signature');
1111

12-
typedef SignatureEncodingListC = Void Function(
13-
Pointer<Void> signature, Pointer<Pointer<Utf8>> typeEncodings);
14-
typedef SignatureEncodingListD = void Function(
15-
Pointer<Void> signature, Pointer<Pointer<Utf8>> typeEncodings);
12+
typedef SignatureEncodingListC = Void Function(Pointer<Void> signature,
13+
Pointer<Pointer<Utf8>> typeEncodings, Int64 decodeRetVal);
14+
typedef SignatureEncodingListD = void Function(Pointer<Void> signature,
15+
Pointer<Pointer<Utf8>> typeEncodings, int decodeRetVal);
1616
final SignatureEncodingListD nativeSignatureEncodingList =
1717
runtimeLib.lookupFunction<SignatureEncodingListC, SignatureEncodingListD>(
1818
'native_signature_encoding_list');

dart_native/lib/src/ios/runtime/message.dart

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,10 @@ dynamic _msgSend(Pointer<Void> target, SEL selector,
8686
}
8787
cache[selector] = signaturePtr;
8888
}
89-
nativeSignatureEncodingList(signaturePtr, typeEncodingsPtrPtr);
89+
nativeSignatureEncodingList(
90+
signaturePtr, typeEncodingsPtrPtr, decodeRetVal ? 1 : 0);
9091

92+
List<Pointer<Utf8>> structTypes = [];
9193
List<NSObjectRef> outRefArgs = [];
9294
int stringTypeBitmask = 0;
9395
Pointer<Pointer<Void>> pointers;
@@ -103,8 +105,10 @@ dynamic _msgSend(Pointer<Void> target, SEL selector,
103105
if (arg is String) {
104106
stringTypeBitmask |= (0x1 << i);
105107
}
106-
Pointer<Utf8> argTypePtr =
107-
nativeTypeEncoding(typeEncodingsPtrPtr.elementAt(i + 1).value);
108+
Pointer<Utf8> argTypePtr = typeEncodingsPtrPtr.elementAt(i + 1).value;
109+
if (argTypePtr.isStruct) {
110+
structTypes.add(argTypePtr);
111+
}
108112
storeValueToPointer(arg, pointers.elementAt(i), argTypePtr);
109113
}
110114
}
@@ -126,19 +130,23 @@ dynamic _msgSend(Pointer<Void> target, SEL selector,
126130
free(pointers);
127131
}
128132

133+
dynamic result;
134+
129135
if (callback == null) {
130-
dynamic result = resultPtr;
136+
result = resultPtr;
131137
if (decodeRetVal) {
132-
Pointer<Utf8> resultTypePtr =
133-
nativeTypeEncoding(typeEncodingsPtrPtr.value);
138+
Pointer<Utf8> resultTypePtr = typeEncodingsPtrPtr.value;
134139
result = loadValueFromPointer(resultPtr, resultTypePtr);
140+
if (resultTypePtr.isStruct) {
141+
structTypes.add(resultTypePtr);
142+
}
135143
outRefArgs.forEach((ref) => ref.syncValue());
136144
}
137-
free(typeEncodingsPtrPtr);
138-
return result;
139-
} else {
140-
free(typeEncodingsPtrPtr);
141145
}
146+
// free struct type memory (malloc on native side)
147+
structTypes.forEach(free);
148+
free(typeEncodingsPtrPtr);
149+
return result;
142150
}
143151

144152
/// Send a message synchronously to [target], which should be an instance in iOS.

0 commit comments

Comments
 (0)