CERT C: правило EXP42-C

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

Описание

Управляйте определением

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

Примеры

развернуть все

Описание

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

Например:

struct structType {
    char member1;
    int member2;
    .
    .
};

structType var1;
structType 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 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

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

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