Posible fuga de un IOBufferMemoryDescriptor en el controlador DriverKit
Tengo un controlador DriverKit para iPadOS. Funciona bien, pero el analizador estático señala una posible fuga que no entiendo. El código marcado está en la propia clase de controlador:
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'
Según el analizador, la llamada a readData()
en la primera línea del método devuelve un OSObject
tipo de IOBufferMemoryDescriptor
con un recuento de retención de +1. Sin embargo, ese método se implementa así:
IOBufferMemoryDescriptor *USBCDCInterface::readData(IOReturn status,
uint32_t actualByteCount,
uint64_t completionTimestamp)
{
pollForData();
return readDataBuffer;
}
Aquí readDataBuffer
hay una variable miembro de USBCDCInterface
, creada cuando el controlador se inicia con una llamada a IOUSBHostInterface::CreateIOBuffer()
:
IOBufferMemoryDescriptor *readDataBuffer = nullptr;
result = dataInterface->CreateIOBuffer(kIOMemoryDirectionIn, 256, &readDataBuffer);
if (result != kIOReturnSuccess) {
return result;
}
this->readDataBuffer = readDataBuffer;
Según tengo entendido OSObject
(y sus subclases) es que utiliza una mecánica de conteo de referencias muy similar a NSObject
. Crearlo, por ejemplo, con CreateIOBuffer()
debería dar como resultado un objeto con un recuento de retención de +1. La USBCDCInterface
instancia que lo creó es propietaria y, por lo tanto, debería release()
serlo cuando termine con él (en USBCDCInterface::free()
). Simplemente devolverlo readData()
no debería transferir la propiedad, y no debería ser responsabilidad de la persona que llama a ese método liberarlo. En particular, llamar release()
al objeto al final CDCDriver::ReadComplete()
provoca que el conductor se estrelle, tal como era de esperar, lo que me hace pensar que es un falso positivo del analizador.
O mi comprensión es errónea y hay algo en la devolución de ese objeto USBCDCInterface::readData()
(por convención o de otro modo) que obliga a la persona que llama a liberarlo (aunque, de nuevo, al hacerlo se bloquea el conductor), o bien se trata de un falso positivo por parte del analizador.
Si se tratara de ObjC/Cocoa, supongo que hay algo en la denominación de mis métodos que hace que el analizador asuma que el readData()
método efectivamente transfiere la propiedad (como un método -copy
o +alloc
), pero no puedo encontrar ninguna documentación sobre convenciones de nomenclatura como esa. , ni he podido determinar si y cómo OSObject
se anotan los métodos con su semántica de administración de memoria.
¿Alguien puede darnos alguna idea?
Debería haber continuado con el pensamiento "si esto fuera Objective-C/Cocoa" hasta su conclusión lógica: OSObject
el recuento sigue la misma convención similar a la de Objective-C y CoreFoundation. Tienes 2 opciones:
- Cambie el nombre de su función para seguir la convención; Entonces, por ejemplo, cámbielo a
GetReadData()
. La gran mayoría de las API DriverKit de Apple siguen la convención. - Anótelo. Creo que la anotación a utilizar en su caso debería ser
DRIVERKIT_RETURNS_NOT_RETAINED
la que normalmente debería evaluarse como__attribute__((os_returns_not_retained))
.