You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中Objective-C端NSData转Byte*调用C++接口崩溃问题

Flutter结合Objective-C调用C++接口崩溃问题排查

问题场景

在Flutter项目中通过平台通道调用Objective-C原生逻辑,进而调用C加解密接口。按照平台通道规则,Flutter层传递的Uint8List类型在OC端对应FlutterStandardTypedData(NSData子类),实现流程为:接收Flutter传递的字节参数转为NSData,拷贝到Byte数组传入C接口处理,处理完成后将结果转回NSData返回给Flutter。代码运行时触发设备崩溃,需要定位错误。

原有实现代码

Flutter端参数发送逻辑

var data = <String, Uint8List>{
  "key": byte,           // 类型为Uint8List
  "value": byteBuffer,   // 类型为Uint8List
};
Uint8List? byteRes;
byteRes = await platform.invokeMethod('SeedDecrypt', data);

Objective-C端(AppDelegate.m)参数接收与处理逻辑

NSData* key = call.arguments[@"key"];
NSData* value = call.arguments[@"value"];

NSUInteger keyLength = [key length];
NSUInteger valueLength = [value length];

Byte* byteKey = (Byte*)malloc(keyLength);
Byte* byteValue = (Byte*)malloc(valueLength);

memcpy(byteKey, [key bytes], keyLength);
memcpy(byteValue, [value bytes], byteLength);

DWORD roundKey[32];

// 调用C++ API
// 函数原型 : void SeedKey(DWORD* roundKey, BYTE* byteKey);
SeedKey(roundKey, byteKey);

// 函数原型 : void Decrypt(BYTE* byteValue, DWORD* roundKey);
Decrypt(byteValue, roundKey);

NSData* res = [NSData dataWithBytes: byteValue length: sizeof(byteValue)];

result(res);

代码中存在的直接错误

  • 内存拷贝变量名笔误:拷贝value对应内存时,传入的长度参数是未定义的byteLength,实际定义的长度变量为valueLength。该问题会导致memcpy读取随机的错误长度值,直接触发内存越界访问崩溃。
  • 返回数据长度计算错误:构造返回NSData时使用sizeof(byteValue)计算长度,byteValue是Byte类型指针,在64位设备上指针固定长度为8字节,和实际解密后的数据长度完全不匹配,会导致返回数据截断,Flutter端解析时也可能触发越界。
  • 堆内存未释放:通过malloc申请的byteKey、byteValue两块堆内存,使用完成后没有调用free释放,会造成内存泄漏,多次调用后内存耗尽也会触发崩溃。
  • 缺少参数类型校验:没有校验通道传递的参数类型是否为NSData,若参数传递异常,直接调用length、bytes等方法会触发找不到方法的崩溃。

修正后的核心处理代码

// 先做参数类型校验,避免非法参数导致崩溃
if (![call.arguments[@"key"] isKindOfClass:[NSData class]] || 
    ![call.arguments[@"value"] isKindOfClass:[NSData class]]) {
    result([FlutterError errorWithCode:@"INVALID_ARGUMENT" 
                               message:@"传入参数类型错误,要求为字节数组" 
                               details:nil]);
    return;
}

NSData* key = call.arguments[@"key"];
NSData* value = call.arguments[@"value"];

NSUInteger keyLength = [key length];
NSUInteger valueLength = [value length];

Byte* byteKey = (Byte*)malloc(keyLength);
Byte* byteValue = (Byte*)malloc(valueLength);

// 修正拷贝长度参数为正确定义的valueLength
memcpy(byteKey, [key bytes], keyLength);
memcpy(byteValue, [value bytes], valueLength);

DWORD roundKey[32];
// 调用C++加解密接口
SeedKey(roundKey, byteKey);
Decrypt(byteValue, roundKey);

// 构造返回结果时使用实际的数据长度valueLength,不要用sizeof计算指针长度
NSData* res = [NSData dataWithBytes:byteValue length:valueLength];

// 释放手动申请的堆内存,避免内存泄漏
free(byteKey);
free(byteValue);

result(res);

额外注意:需要确认C层的Decrypt接口是否为原地解密、输出长度是否和输入长度一致,如果解密后长度变化需要按照实际输出长度构造NSData,避免C层内部内存越界。

内容的提问来源于stack exchange,提问作者Jungwon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 22:48:22