Compartir a través de


Uso de la función _analysis_assume para suprimir defectos falsos

Puede proporcionar al Comprobador de controladores estáticos (SDV) información adicional sobre el código fuente del controlador para que durante la comprobación pueda suprimir los informes de defectos falsos. Los defectos falsos se producen cuando SDV informa de una infracción de regla aparente, pero en una situación en la que el controlador está actuando correctamente.

Para proporcionar a SDV esta información adicional, use la función __analysis_assume . La función tiene la siguiente sintaxis:

__analysis_assume( expression ) 

Donde expression puede ser cualquier expresión que se supone que se evalúa como true.

Cuando se usa esta función, SDV supone que la condición representada por la expresión es verdadera en el punto en el que aparece la función __analysis_assume . Las herramientas de análisis estáticos solo usan la función __analysis_assume . El compilador omite la función.

Si usa __analysis_assume, es fundamental que esté seguro de la validez de la suposición que está realizando. Si resulta que su suposición es falsa, ya sea ahora o en el futuro, podría suprimir un verdadero defecto. Se recomienda agregar siempre un comentario al código que explique por qué usa la función __analysis_assume . Si no puede escribir una razón para la suposición, no suprima el defecto.

Debe agregar la función __analysis_assume según sea necesario, siempre que encuentre defectos falsos que pueda suprimir de forma segura.

Ejemplos

En el ejemplo de código siguiente, la regla de KMDF RequestCompletedLocal notifica un defecto. Se trata de un defecto falso porque SDV no puede interpretar correctamente la instrucción switch y, por lo tanto, no entra en la rama donde se completa la solicitud.

En esta instrucción switch , hay seis casos posibles. El controlador ha definido seis códigos IOCTL, por lo que el controlador definitivamente tomará una de las ramas. Si se toma una de las ramas, la solicitud se completa correctamente.

VOID
PortIOEvtIoDeviceControl(
      __in WDFQUEUE     Queue,
      __in WDFREQUEST   Request,
      __in size_t       OutputBufferLength,
  __in size_t       InputBufferLength,
  __in ULONG        IoControlCode
     )
 
     PDEVICE_CONTEXT devContext = NULL;
     WDFDEVICE device;

     PAGED_CODE();
 
     device = WdfIoQueueGetDevice(Queue);
 
     devContext = PortIOGetDeviceContext(device);
 
     switch(IoControlCode)
         case IOCTL_GPD_READ_PORT_UCHAR:
         case IOCTL_GPD_READ_PORT_USHORT:
         case IOCTL_GPD_READ_PORT_ULONG:
             PortIOIoctlReadPort(devContext,
                                 Request,
                                 OutputBufferLength,
                                 InputBufferLength,
                                 IoControlCode);
             break;

 
         case IOCTL_GPD_WRITE_PORT_UCHAR:
         case IOCTL_GPD_WRITE_PORT_USHORT:
         case IOCTL_GPD_WRITE_PORT_ULONG:    
             PortIOIoctlWritePort(devContext,
                                  Request,
                                  OutputBufferLength,
                                  InputBufferLength,
                                  IoControlCode);
             break;
 
     }
 
}

Para suprimir de forma segura el defecto falso, use la función __analysis_assume para especificar que IoControlCode se garantiza que sea una de las E/S POR SEGUNDO definidas por el controlador.

VOID
PortIOEvtIoDeviceControl(
      __in WDFQUEUE     Queue,
      __in WDFREQUEST   Request,
      __in size_t       OutputBufferLength,
      __in size_t       InputBufferLength,
      __in ULONG        IoControlCode
     )
 
     PDEVICE_CONTEXT devContext = NULL;
     WDFDEVICE device;

     PAGED_CODE();
 
     device = WdfIoQueueGetDevice(Queue);
 
     devContext = PortIOGetDeviceContext(device);

/* Use __analysis_assume to suppress a false defect for the SDV RequestCompletedLocal rule. 
There are only 6 possible IOCTLs for IoControlCode; each case is covered in the switch statement.
*/

 __analysis_assume( IoControlCode == IOCTL_GPD_READ_PORT_UCHAR || \
                       IoControlCode == IOCTL_GPD_READ_PORT_USHORT|| \
                       IoControlCode == IOCTL_GPD_READ_PORT_ULONG || \
                       IoControlCode == IOCTL_GPD_WRITE_PORT_UCHAR|| \
                       IoControlCode == IOCTL_GPD_WRITE_PORT_USHORT|| \
                       IoControlCode == IOCTL_GPD_WRITE_PORT_ULONG);

     switch(IoControlCode)
         case IOCTL_GPD_READ_PORT_UCHAR:
         case IOCTL_GPD_READ_PORT_USHORT:
         case IOCTL_GPD_READ_PORT_ULONG:
             PortIOIoctlReadPort(devContext,
                                 Request,
                                 OutputBufferLength,
                                 InputBufferLength,
                                 IoControlCode);
             break;

 
         case IOCTL_GPD_WRITE_PORT_UCHAR:
         case IOCTL_GPD_WRITE_PORT_USHORT:
         case IOCTL_GPD_WRITE_PORT_ULONG:    
             PortIOIoctlWritePort(devContext,
                                  Request,
                                  OutputBufferLength,
                                  InputBufferLength,
                                  IoControlCode);
             break;
 
     }
 
}

Para obtener otro ejemplo de cómo puede usar __analysis_assume, vea el código de ejemplo que se usa en Uso de __sdv_save_request y __sdv_retrieve_request para llamadas a procedimiento diferido. En el ejemplo se muestra cómo usar __sdv_save_request y __sdv_retrieve_request para DPC (elementos de trabajo, temporizadores, etc.). La función __analysis_assume se usa para suprimir defectos falsos que podrían resultar de otro modo.