CERT C++: PRE32-C

Не используйте директивы препроцессора в вызовах функциональных макросов

Описание

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

Не используйте директивы препроцессора в вызовах функциональных макросов.[1]

Реализация Polyspace

Эта проверка проверяет наличие директивы Preprocessor в аргументе macro.

Примеры

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

Проблема

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

Для образца, a #ifdef оператор возникает в аргументе к memcpy функция. The memcpy функция может быть реализована как макрос.

memcpy(dest, src,
    #ifdef PLATFORM1
      12
    #else
      24
    #endif
  );
Шашечные флаги аналогичного использования в printf и assert, который также может быть реализован как макросы.

Риск

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

#define min(X, Y)  ((X) < (Y) ? (X) : (Y))
Когда вы звоните min(1,2), он заменяется телом ((X) < (Y) ? (X) : (Y)). X и Y заменяются на 1 и 2.

Согласно Стандарту C11 (раздел 6.10.3), если список аргументов в сам функциональный макрос имеет директивы предварительной обработки, подстановка аргумента во время предварительной обработки не определена.

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

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

Например, чтобы выполнить memcpy с различными аргументами, основанными на #ifdef директива, вызов memcpy несколько раз в #ifdef директивные ветви.

#ifdef PLATFORM1
    memcpy(dest, src, 12);
#else
    memcpy(dest, src, 24);
#endif

Пример - Директивы в функциональных макросах
#include <stdio.h>

#define print(A) printf(#A)

void func(void) {
    print(
#ifdef SW
          "Message 1"
#else
          "Message 2"
#endif
         );
}

В этом примере директивы препроцессора #ifdef и #endif происходит в аргументе функционального макроса print().

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

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

#include <stdio.h>

#define print(A) printf(#A)

void func(void) {
#ifdef SW
        print("Message 1");
#else  
        print("Message 2");
#endif 
}

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

Группа: 49. Разное (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 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

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

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