Posible fuga de un IOBufferMemoryDescriptor en el controlador DriverKit

Resuelto Andrew Madsen asked hace 55 años • 1 respuestas

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'

Captura de pantalla de los resultados del analizador estático

Según el analizador, la llamada a readData()en la primera línea del método devuelve un OSObjecttipo de IOBufferMemoryDescriptorcon 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í readDataBufferhay 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 USBCDCInterfaceinstancia 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 -copyo +alloc), pero no puedo encontrar ninguna documentación sobre convenciones de nomenclatura como esa. , ni he podido determinar si y cómo OSObjectse anotan los métodos con su semántica de administración de memoria.

¿Alguien puede darnos alguna idea?

Andrew Madsen avatar Jan 01 '70 08:01 Andrew Madsen
Aceptado

Debería haber continuado con el pensamiento "si esto fuera Objective-C/Cocoa" hasta su conclusión lógica: OSObjectel 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_RETAINEDla que normalmente debería evaluarse como __attribute__((os_returns_not_retained)).
pmdj avatar Feb 16 '2024 06:02 pmdj