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

从C++类方法返回KMM创建的NSObject触发EXC_BAD_ACCESS的原因及解决方法

C++返回KMM创建的NSObject触发EXC_BAD_ACCESS异常的原因与解决方法

在从C++类方法返回由Kotlin Multiplatform(KMM)创建的NSObject时,触发了EXC_BAD_ACCESS异常(由Sentry错误追踪系统上报),以下是对问题原因的分析及预防方案:

问题原因

  • 内存管理逻辑冲突:KMM生成的NSObject默认采用ARC(自动引用计数)管理内存,但你的C代码手动调用了retain和release,这会和ARC的自动计数逻辑冲突。当ARC自动释放SMLMountPoint实例后,C类里的m_mountPoint就变成了野指针,调用getMountPoint访问时直接触发崩溃。
  • 对象生命周期不匹配:在实例化逻辑中,旧的MountPoint被调用deleteLater()后,其析构函数会执行[m_mountPoint release],但如果此时SMLMountPoint已经被ARC释放,就会导致重复释放或访问已回收的内存。另外,用alloc创建的point变量,其内存管理和C++的手动操作叠加,进一步加剧了生命周期混乱。
  • 野指针直接访问:崩溃发生在getMountPoint返回m_mountPoint的位置,说明此时m_mountPoint指向的内存已经被释放,变成无效指针,访问0x10这个无效地址触发了SEGV_NOOP错误。

预防与解决方法

  • 统一内存管理策略:删掉C++代码里的手动retain/release,交给ARC全权处理SMLMountPoint的内存。修改后的代码如下:

    AgraQML::MountPoint::MountPoint(SMLMountPoint* point) {
        m_mountPoint = point; // 移除[point retain],ARC自动管理引用
    }
    
    AgraQML::MountPoint::~MountPoint() {
        // 移除[m_mountPoint release],ARC自动释放对象
    }
    

    注意:要保证SMLMountPoint实例在MountPoint对象的生命周期内不会被ARC提前释放,必要时可以在Objective-C代码中用__strong修饰符延长其生命周期。

  • 修正实例化逻辑的内存操作:用alloc创建SMLMountPoint后,ARC会自动处理其引用计数,不需要手动release。当旧的MountPoint被deleteLater()时,因为已经移除了手动release操作,不会再和ARC的释放逻辑冲突。

  • 添加空值检查避免野指针:在getMountPoint方法里先判断m_mountPoint是否为nil,避免返回无效指针:

    SMLMountPoint* AgraQML::MountPoint::getMountPoint() const {
        return m_mountPoint ? m_mountPoint : nullptr;
    }
    

    同时,在调用getMountPoint返回的对象之前,也要先做空值判断,再执行后续操作。

  • 用Objective-C++特性封装对象:可以在C++类中用__strong修饰m_mountPoint,让ARC自动管理其引用,确保内存操作一致:

    // 在MountPoint类中定义成员变量
    __strong SMLMountPoint* m_mountPoint;
    
    // 构造函数无需手动retain
    AgraQML::MountPoint::MountPoint(SMLMountPoint* point) : m_mountPoint(point) {}
    
    // 析构函数无需手动release
    AgraQML::MountPoint::~MountPoint() {}
    

相关原代码片段

C++ MountPoint类原代码

AgraQML::MountPoint::MountPoint(SMLMountPoint* point) {
    [point retain];
    m_mountPoint = point;
}

AgraQML::MountPoint::~MountPoint() {
    [m_mountPoint release];
}

SMLMountPoint* AgraQML::MountPoint::getMountPoint() const {
    return m_mountPoint;
}

实例化逻辑原代码

SMLMountPoint *point = [[SMLMountPoint alloc] initWithRecord:mountPointRecord.toNSString()];
auto oldMountPoint = findChild<AgraQML::MountPoint*>();
AgraQML::MountPoint* mountPoint;
if (oldMountPoint == nullptr || oldMountPoint->path() != QString::fromNSString(point.path)) {
    // 创建新的MountPoint
    mountPoint = new AgraQML::MountPoint(point);
    mountPoint->setParent(this);
    if (oldMountPoint != nullptr) // 移除旧的MountPoint
        oldMountPoint->deleteLater();
} else {
    // 使用旧的MountPoint
    mountPoint = oldMountPoint;
}

异常信息

Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: SEGV_NOOP at 0x0000000000000010
Crashed Thread: 0

Application Specific Information:
__cxa_guard_release > _setInvalidatesViewsOnAppearanceChange: > application:didFinishLaunchingWithOptions: >
KERN_INVALID_ADDRESS at 0x10.

Thread 0 Crashed:
0   AgraGPS                         0x2009acb74         AgraQML::MountPoint::getMountPoint (MountPoint.mm:16)
1   AgraGPS                         0x20099877c         AgraQML::NTRIP::restoreGetData (NTRIP.mm:61)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 20:24:53