CERT C: Rule EXP42-C

Не сравнивайте данные заполнения

Описание

Определение правила

Не сравнивайте данные заполнения.[1]

Реализация Polyspace

Эта проверка проверяет сравнение данных заполнения с памятью.

Примеры

расширить все

Проблема

Сравнение данных заполнения в память происходит, когда вы используете memcmp функция для сравнения двух структур в целом. В процессе сравниваются бессмысленные данные, хранимые в заполнении структуры.

Для образца:

typedef struct structType {
    char member1;
    int member2;
    //...
}myStruct;

myStruct var1;
myStruct var2;
//...
if(memcmp(&var1,&var2,sizeof(var1))) 
{//...}

Риск

Если представители структуры имеют различные типы данных, ваш компилятор вводит дополнительное заполнение для выравнивания данных в памяти. Пример заполнения см. в разделе Higher Estimate of Local Variable Size.

Содержимое этих дополнительных байтов заполнения бессмысленно. Стандарт C позволяет содержимое этих байтов быть неопределенным, предоставляя различным компиляторам широту для реализации собственного заполнения. Если вы выполняете байтовое сравнение структур с memcmp, вы сравниваете даже бессмысленные данные, хранящиеся в заполнении. Вы можете прийти к ложному выводу, что две структуры данных не равны, даже если их соответствующие представители имеют одинаковое значение.

Зафиксировать

Вместо сравнения двух структур в одной попытке сравните представителя структур по представителям.

Для эффективного кода запишите функцию, которая делает представитель сравнения по представителям. Используйте эту функцию для сравнения двух структур.

Можно использовать memcmp для байтового сравнения структур только в том случае, если известно, что структуры не содержат заполнения. Обычно, чтобы предотвратить заполнение, вы используете определенные атрибуты или прагмы, такие как #pragma pack. Однако эти атрибуты или прагмы не поддерживаются всеми компиляторами и делают вашу реализацию кода зависимой. Если ваши структуры содержат битовые поля, использование этих атрибутов или прагм не может предотвратить заполнение.

Пример - Структуры по сравнению с memcmp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define fatal_error() abort()

typedef struct s_padding
{
    char c;            
    int i;
    unsigned int bf1:1;    
    unsigned int bf2:2;
    unsigned char buffer[20];
} S_Padding ;

/* Function that guarantees safe access to the input memory */
extern int trusted_memory_zone(void *ptr, size_t sz); 

int func(const S_Padding *left, const S_Padding *right)
{

    if (!trusted_memory_zone((void *)left, sizeof(S_Padding)) ||
        !trusted_memory_zone((void *)right, sizeof(S_Padding))) {
        fatal_error();
    }

    if (0 == memcmp(left, right, sizeof(S_Padding))) 
    {
        return 1;
    }
    else
        return 0;
}

В этом примере memcmp сравнивает байт за байтом две структуры, которые left и right указать на. Даже если значения, сохраненные в представителях структуры, одинаковы, сравнение может показать неравенство, если бессмысленные значения в байтах заполнения не совпадают.

Коррекция - Сравнение представителей структур по представителям

Одной из возможных коррекций является сравнение отдельных представителей структуры.

Примечание

Можно сравнить целые массивы при помощи memcmp. Все представители массива имеют совпадающий тип данных. Заполнение байтов не требуется для хранения массивов.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define fatal_error() abort()

typedef struct s_padding
{
    char c;         
    int i;
    unsigned int bf1:1;    
    unsigned int bf2:2;
    unsigned char buffer[20];
} S_Padding ;

/* Function that guarantees safe access to the input memory */
extern int trusted_memory_zone(void *ptr, size_t sz); 

int func(const S_Padding *left, const S_Padding *right)
{
    if (!trusted_memory_zone((void *)left, sizeof(S_Padding)) ||
        !trusted_memory_zone((void *)right, sizeof(S_Padding))) {
        fatal_error();
    }

    return ((left->c == right->c) &&                
            (left->i == right->i) &&
            (left->bf1 == right->bf1) &&
            (left->bf2 == right->bf2) &&
            (memcmp(left->buffer, right->buffer, 20) == 0)); 
}

Проверяйте информацию

Группа: Правило 03. Выражения (EXP)
Введенный в R2019a

[1] Это программное обеспечение было создано MathWorks, включающее фрагменты: «Сайт SEI CERT-C», © 2017 Университет Карнеги Меллон, Веб-сайт SEI CERT-C + + © 2017 Университет Карнеги Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОН И/ИЛИ ЕГО ИНЖЕНЕРНОГО ИНСТИТУТА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ НА БАЗИСЕ «КАК ЕСТЬ». УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБОГО ВОПРОСА, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИЮ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ КОММЕРЧЕСКОЙ ВЫГОДЫ, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.

Это программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллон или его Институтом программной инженерии.