Поделиться через


Использование функции _analysis_assume для подавления ложных дефектов

Вы можете предоставить статическому средству проверки драйверов (SDV) дополнительные сведения об исходном коде драйвера, чтобы во время проверки можно было подавлять отчеты о ложных дефектах. Ложные дефекты возникают, когда SDV сообщает о явном нарушении правил, но в ситуации, когда драйвер работает правильно.

Чтобы предоставить SDV эти дополнительные сведения, используйте функцию __analysis_assume . Функция имеет следующий синтаксис:

__analysis_assume( expression ) 

Где выражением может быть любое выражение, которое должно иметь значение true.

При использовании этой функции SDV предполагает, что условие, представленное выражением , имеет значение true в точке, где отображается функция __analysis_assume . Функция __analysis_assume используется только средствами статического анализа. Функция игнорируется компилятором.

Если вы используете __analysis_assume, крайне важно, чтобы вы были уверены в обоснованности допущения, которое вы делаете. Если окажется, что ваше предположение ложно сейчас или в будущем, вы можете подавлять истинный дефект. Рекомендуется всегда добавлять в код комментарий, объясняющий, почему вы используете функцию __analysis_assume . Если вы не можете написать причину для предположения, не подавляйте дефект.

При необходимости следует добавлять функцию __analysis_assume при обнаружении ложных дефектов, которые можно безопасно подавлять.

Примеры

В следующем примере кода правило KMDF RequestCompletedLocal сообщает о дефекте. Это ложный дефект, так как SDV не может правильно интерпретировать инструкцию switch и, следовательно, не входит в ветвь, в которой выполняется запрос.

В этом операторе switch существует шесть возможных вариантов. Драйвер определил шесть кодов IOCTL, поэтому драйвер обязательно возьмет одну из ветвей. Если берется одна из ветвей, запрос завершается успешно.

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;
 
     }
 
}

Чтобы безопасно подавить ложный дефект, используйте функцию __analysis_assume , чтобы указать, что IoControlCode гарантированно является одним из ioCTL, определенных драйвером.

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;
 
     }
 
}

Еще один пример использования __analysis_assume см. в примере кода, который используется в разделе Использование __sdv_save_request и __sdv_retrieve_request для отложенных вызовов процедур. В примере показано, как использовать __sdv_save_request и __sdv_retrieve_request для DPC (рабочие места, таймеры и т. д.). Функция __analysis_assume используется для подавления ложных дефектов, которые могут возникнуть в противном случае.