Статический анализ покрытия рассматривает char или числа как int в C

Обе переменные LHS и RHS являются переменной uint8_t, но о проблеме сообщается как "преобразование типа int в unsigned char". Я не понимаю, как это может быть проблемой?

То же самое применимо для 8-битных чисел.

Все переменные, перечисленные в обоих выпусках, - uint8_t

Выпуск 1)

CID 147563 (#2 of 2): Coding standard violation (CERT INT31-C)3. cert_violation: 
Casting (uint8_t)apX_compY_bitmask from int to unsigned char without checking its 
value may result in lost or misinterpreted data.

/* AP_X_Flash_Component_Y_Authenticated */
static uint8_t AP_component_require_auth; 

//Local variable:

uint8_t apX_compY_bitmask = 0u, port;

// other operations

AP_component_require_auth |= (uint8_t)apX_compY_bitmask;

Выпуск 2)

CID 148170 (#1 of 1): Coding standard violation (CERT INT31-C)5. cert_violation: 
Casting major_revision >> 3 from int to unsigned char without checking its 
value may result in lost or misinterpreted data.

Аргумент функции:

void sb_rollb_prot_AP_FW_in_use_update(uint8_t img_idx, uint8_t port, uint8_t major_revision, bool primary_image)

//Local Variable
uint8_t x_loc, y_loc;
y_loc = major_revision >> 3;

1 ответ

Чтобы понять, что вызвало предупреждение, вы должны понимать (или, по крайней мере, осознавать) несколько загадочные, а иногда и неожиданные правила продвижения типов в языке C.

Поразрядные и арифметические операторы C работают с int или unsigned intили более крупные типы, поэтому при представлении операндов меньшего типа происходит неявное продвижение:

Рассмотрим, например, этот "эксперимент":

#include <stdint.h>
#include <stdio.h>

int main()
{
    uint8_t a ;
    uint8_t b ;

    printf( "sizeof(a) = %zu\n", sizeof(a) ) ;
    printf( "sizeof(b) = %zu\n", sizeof(b) ) ;
    printf( "sizeof(a | b) = %zu\n", sizeof(a | b) ) ;
    printf( "sizeof((uint8_t)(a | b)) = %zu\n", sizeof((uint8_t)(a | b)) ) ;
    printf( "sizeof(a >> 3) = %zu\n", sizeof(a >> 3) ) ;
    printf( "sizeof((uint8_t)(a >> 3)) = %zu\n", sizeof((uint8_t)(a >> 3)) ) ;


    return 0;
}

Выход (где int 32-битный) это:

sizeof(a) = 1
sizeof(b) = 1
sizeof(a | b) = 4
sizeof((uint8_t)(a | b)) = 1
sizeof(a >> 3) = 4
sizeof((uint8_t)(a >> 3)) = 1

Итак, в первом случае:

AP_component_require_auth |= (uint8_t)apX_compY_bitmask;

В uint8_t cast не имеет смысла, поскольку он уже является этим типом, и уж точно не отменяет неявное преобразование.

Я не знаком с CERT-C или Coverity, но в аналогичных инструментах, которые я использовал, неявное приведение может использоваться, чтобы утверждать, что выражение является преднамеренным:

AP_component_require_auth = (uint_8_t)(AP_component_require_auth | apX_compY_bitmask) ;

y_loc = (uint8_t)(major_revision >> 3) ;

Как видите, решить эту проблему с помощью |= потому что вы не можете затем применить результат | выражение перед присваиванием.

Однако часто лучше поддерживать соглашение о типах и избегать явных или неявных преобразований и использовать int, unsigned или целочисленный тип равного / большего размера, если нет веских причин использовать меньший тип.

В обоих случаях проблема заключается в присвоении int размер шрифта в uint8_t. Хотя первое предупреждение несколько сбивает с толку - вероятно, из-за использования|=- предотвращение формы представления неявно приведенного выражения; я думаю, вы должны получить ту же ошибку без ненужного приведения. Инструмент статического анализа, с которым я знаком, мог бы сказать что-то вроде:

неявное преобразование в меньший тип при присваивании

в обоих случаях, что, на мой взгляд, намного яснее.

Предупреждение Coverity краткое и минимальное; если вы перейдете непосредственно к стандарту, который он применяет, он будет более явным и дает обоснование, примеры и решения: https://wiki.sei.cmu.edu/confluence/display/c/INT31-C.+Ensure+that+ целочисленные + преобразования + не + приводят + к + потерянным + или + неверно интерпретированным + данным

Другие вопросы по тегам