exponenta event banner

CERT C: MSC40-C правил

Не нарушать ограничения

Описание

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

Не нарушайте ограничения. [1 ]

Внедрение Polyspace

Эта проверка проверяет, не соблюдено ли встроенное ограничение.

Примеры

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

Проблема

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

Например, var является изменяемым static переменная, определенная в inline функция func. g_step является изменяемой статической переменной области действия файла, на которую ссылается одна и та же встроенная функция.

static int g_step;
inline void func (void) {
   static int var = 0;
   var += g_step;
}

Риск

При изменении статической переменной в нескольких вызовах функций ожидается изменение одной и той же переменной в каждом вызове. Например, каждый раз, когда вы звоните func, тот же экземпляр var1 увеличивается, но отдельный экземпляр var2 увеличивается.

void func(void) {
   static var1 = 0;
   var2 = 0;
   var1++;
   var2++;
}

Если функция имеет определение inlined и non-inlined (в отдельных файлах), при вызове функции стандарт C позволяет компиляторам использовать либо inlined, либо non-inlined форму (см. ISO ®/IEC 9899:2011, sec. 6.7.4). Если компилятор использует встроенное определение в одном вызове, а неинлинированное определение в другом, изменение одной и той же переменной в обоих вызовах больше не выполняется. Это поведение не соответствует ожиданиям от статической переменной.

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

Используйте одно из следующих исправлений:

  • Если изменение переменной не планируется, объявите ее как const.

    Если переменная не изменяется, то о неожиданном изменении речи не идет.

  • Сделать переменную не -static. Удалить static квалификатор из объявления.

    Если переменная определена в функции, она становится обычной локальной переменной. Если она определена в области файла, она становится внешней переменной. Убедитесь, что это изменение в поведении именно то, что вы намереваетесь.

  • Выполнение функции static. Добавить static квалификатор к определению функции.

    При выполнении функции static, файл с встроенным определением всегда использует встроенное определение при вызове функции. Другие файлы используют другое определение функции. Вопрос о том, какое определение функции используется, не оставлен на усмотрение компилятора.

Пример - Использование статической переменной в встроенном и внешнем определении
/* file1. c  : contains inline definition of get_random()*/

inline unsigned int get_random(void) 
{

    static unsigned int m_z = 0xdeadbeef; 
    static unsigned int m_w = 0xbaddecaf; 

    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16); 
    m_w = 18000 * (m_w & 65535) + (m_w >> 16); 
    return (m_z << 16) + m_w;   
}


int call_get_random(void)
{
    unsigned int rand_no;
    int ii;
    for (ii = 0; ii < 100; ii++) {
         rand_no = get_random();
    }
    rand_no = get_random();
    return 0;
}
/* file2. c  : contains external definition of get_random()*/

extern unsigned int get_random(void)
{
    /* Initialize seeds */
    static unsigned int m_z = 0xdeadbeef;
    static unsigned int m_w = 0xbaddecaf;
    
    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
    return (m_z << 16) + m_w;
}

В этом примере: get_random() имеет встроенное определение в file1.c и внешнее определение в file2.c. Когда get_random вызывается в file1.cкомпиляторы могут свободно выбирать, использовать встроенное или внешнее определение.

В зависимости от используемого определения, вы можете изменить или не изменить версию m_z и m_w в встроенной версии get_random(). Такое поведение противоречит обычным ожиданиям от статической переменной. При звонке get_random(), вы ожидаете всегда изменять то же самое m_z и m_w.

Коррекция - Сделать встроенную функцию статической

Одна из возможных корректировок состоит в том, чтобы сделать встроенное get_random() статический. Независимо от компилятора, вызовы get_random() в file1.c затем используйте встроенное определение. Звонки в get_random() в других файлах используется внешнее определение. Это исправление устраняет неоднозначность того, какое определение используется и изменяются ли статические переменные в этом определении.

/* file1. c  : contains inline definition of get_random()*/

static inline unsigned int get_random(void) 
{

    static unsigned int m_z = 0xdeadbeef; 
    static unsigned int m_w = 0xbaddecaf; 

    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16); 
    m_w = 18000 * (m_w & 65535) + (m_w >> 16); 
    return (m_z << 16) + m_w;   
}


int call_get_random(void)
{
    unsigned int rand_no;
    int ii;
    for (ii = 0; ii < 100; ii++) {
         rand_no = get_random();
    }
    rand_no = get_random();
    return 0;
}
/* file2. c  : contains external definition of get_random()*/

extern unsigned int get_random(void)
{
    /* Initialize seeds */
    static unsigned int m_z = 0xdeadbeef;
    static unsigned int m_w = 0xbaddecaf;
    
    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
    return (m_z << 16) + m_w;
}

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

Группа: Правило 48. Разное (MSC)
Представлен в R2019a

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

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

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