我有一个适用于 iPadOS 的 DriverKit 驱动程序。它工作正常,但静态分析器标记了我不明白的可能泄漏。标记的代码位于驱动程序类本身中:
void IMPL(CDCDriver, ReadComplete)
{
// Simply trampolines back to USBCDCInterface where the read is actually handled
IOBufferMemoryDescriptor *readDataBuffer = ivars->cdcInterface->readData(status, actualByteCount, completionTimestamp);
if (actualByteCount > 0) {
os_log(OS_LOG_DEFAULT, "[Driver] Got %u bytes of data!", actualByteCount);
if (ivars->client != nullptr) {
ivars->client->dataWasReceived(readDataBuffer, actualByteCount);
}
}
} // [!] Potential leak of an object stored into 'readDataBuffer'
根据分析器,该方法第一行对
readData()
的调用会返回 OSObject
类型的 IOBufferMemoryDescriptor
,保留计数为 +1。然而,该方法的实现如下:
IOBufferMemoryDescriptor *USBCDCInterface::readData(IOReturn status,
uint32_t actualByteCount,
uint64_t completionTimestamp)
{
pollForData();
return readDataBuffer;
}
这里,
readDataBuffer
是USBCDCInterface
的成员变量,在驱动程序通过调用IOUSBHostInterface::CreateIOBuffer()
启动时创建:
IOBufferMemoryDescriptor *readDataBuffer = nullptr;
result = dataInterface->CreateIOBuffer(kIOMemoryDirectionIn, 256, &readDataBuffer);
if (result != kIOReturnSuccess) {
return result;
}
this->readDataBuffer = readDataBuffer;
我对
OSObject
(及其子类)的理解是,它使用与 NSObject
非常相似的引用计数机制。创建它,例如与 CreateIOBuffer()
应该会产生一个保留计数 +1 的对象。创建它的 USBCDCInterface
实例拥有它,因此当它完成时应该 release()
(在 USBCDCInterface::free()
中)。简单地从 readData()
返回它不应该转移所有权,并且该方法的调用者不应该有责任释放它。值得注意的是,正如我所期望的那样,在 release()
末尾的对象上调用 CDCDriver::ReadComplete()
会导致驱动程序崩溃,这让我认为这是分析器的误报。
我的理解有缺陷,并且从
USBCDCInterface::readData()
返回该对象(按照惯例或其他方式)要求调用者释放它(尽管如此,这样做会使驱动程序崩溃),否则这是一个误报分析仪部分。
如果这是 ObjC/Cocoa,我猜想我的方法的命名有些问题导致分析器假设
readData()
方法有效地转移了所有权(如 -copy
或 +alloc
方法),但我可以找不到任何类似的命名约定的文档,我也无法弄清楚是否/如何使用内存管理语义来注释 OSObject
方法。
任何人都可以提供任何见解吗?
您应该继续“如果这是 Objective-C/Cocoa”的想法,得出其逻辑结论:
OSObject
引用计数遵循与 Objective-C 和 CoreFoundation 相同的语义。您有 2 个选择:
GetReadData()
。 Apple 自己的 DriverKit API 绝大多数都遵循约定。DRIVERKIT_RETURNS_NOT_RETAINED
,通常应评估为 __attribute__((os_returns_not_retained))
。