CERT C: Rec. MSC12-C

Обнаружение и удаление кода, который не влияет или никогда не выполняется

Описание

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

Обнаружение и удаление кода, который не имеет эффекта или никогда не выполняется.[1]

Реализация Polyspace

Эта проверка проверяет на наличие следующих проблем:

  • Недоступный код.

  • Мертвый код.

  • Бесполезно, если.

  • Писать без дальнейшего чтения.

Примеры

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

Проблема

Проблема возникает, когда ваш проект содержит код, который недоступен.

Polyspace® Bug Finder™ и Polyspace Code Prover™ по-разному проверить это правило кодирования. Анализы могут привести к различным результатам.

Проверка выполнения Code Prover на недостижимый код показывает больше случаев, чем MISRA® проверка этого правила. См. также Unreachable code (Polyspace Code Prover). Проверка во время выполнения выполняет более исчерпывающий анализ. В процессе проверки могут быть показаны некоторые образцы, которые не являются строго недоступным кодом, но недоступны только в контексте анализа. Например, в следующем коде проверка во время выполнения показывает потенциальное деление на нуль в первой линии, а затем удаляет нулевое значение flag для остальной части анализа. Поэтому он рассматривает if блок недоступен.

val=1.0/flag;
if(!flag) {}
Проверка MISRA предназначена для предотвращения такого рода результатов.

Риск

Если программа не показывает какое-либо неопределенное поведение, недоступный код не может выполняться. Недоступный код не может повлиять на выход программы. Наличие недостижимого кода может указывать на ошибку в логике программы. Недоступный код, что компилятор не удаляет ресурсы отходов, например:

  • Он занимает пространство в целевой памяти машины.

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

  • В цикле это может предотвратить пребывание всего цикла в кэше команд.

Пример - Код следующего return Оператор
enum light { red, amber, red_amber, green };
void report_color(enum light);
enum light next_light ( enum light color )
{
    enum light res;

    switch ( color )
    {
    case red:
        res = red_amber;
        break;
    case red_amber:
        res = green;
        break;
    case green:
        res = amber;
        break;
    case amber:
        res = red;
        break;
    default:
    {
        error_handler ();
        break;
    }
    }

    report_color(res);
    return res;
    res = color;     /* Non-compliant */
}

В этом примере правило нарушается, потому что существует недоступная операция, следующая за return оператор.

Проблема

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

Polyspace Bug Finder обнаруживает бесполезные операции записи во время анализа.

Polyspace Code Prover не обнаруживает бесполезных операций записи. Например, если вы присвоите значение локальной переменной, но не читаете его позже, Polyspace Code Prover не обнаруживает это бесполезное назначение. Используйте Polyspace Bug Finder, чтобы обнаружить такие бесполезные операции записи. Для получения дополнительной информации смотрите C:2012 MISRA в Polyspace Bug Finder.

В Code Prover также можно увидеть различие в результатах, основанную на вашем выборе для опции Verification level (-to) (Polyspace Code Prover). Смотрите раздел «Проверка на нарушения стандартов кодирования».

Риск

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

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

Операции с языковыми расширениями, такими как __asm ( "NOP" ); не считаются мертвым кодом.

Пример - Избыточные операции
extern volatile unsigned int v;
extern char *p;

void f ( void ) {
    unsigned int x;


    ( void ) v;      /* Compliant - Exception*/
    ( int ) v;       /* Non-compliant  */
    v >> 3;          /* Non-compliant  */

    x = 3;           /* Non-compliant - Detected in Bug Finder only */

    *p++;            /* Non-compliant  */
    ( *p )++;        /* Compliant  */
}

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

  • Операции (int) и >> на переменной v являются избыточными, поскольку результаты не используются.

  • Область операции = избыточен, потому что локальная переменная x не считывается после операции.

  • Область операции * на p++ является избыточным, поскольку результат не используется.

Правило не нарушается, когда:

  • Переменная приведена к void. Приведение указывает, что вы намеренно не используете значение.

  • Используется результат операции. Например, операция * на p не является избыточным, потому что *p приращение.

Проблема

Эта проблема возникает на if-операторы, где условие всегда верно. Этот дефект возникает только в операторах if, у которых нет оператора else-.

Этот дефект показывает ненужные if-операторы, когда нет различий в выполнении кода, если if-оператор удаляется.

Риск

Ненужные if операторы часто указывают на ошибку кодирования. Возможно, if условие закодировано неправильно или if оператор не требуется вообще.

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

Исправление зависит от первопричины дефекта. Например, первопричиной может быть условие ошибки, которое дважды проверяется на одном и том же пути выполнения, делая вторую проверку избыточной.

Часто детали результата показывают последовательность событий, которые привели к дефекту. Вы можете реализовать исправление на любом событии в последовательности. Если сведения о результате не отображают историю событий, можно отследить их с помощью опций правого щелчка в исходном коде и просмотреть предыдущие связанные события. Смотрите также Результаты интерпретации Bug Finder в интерфейсе пользователя Polyspace Desktop.

См. примеры исправлений ниже.

Если избыточное условие представляет практики защитного кодирования, и вы не хотите устранять проблему, добавьте комментарии к своему результату или коду, чтобы избежать другого обзора. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.

Пример - if с перечисленным типом
typedef enum _suit {UNKNOWN_SUIT, SPADES, HEARTS, DIAMONDS, CLUBS} suit;
suit nextcard(void);
void do_something(suit s);

void bridge(void)
{
    suit card = nextcard();
    if ((card < SPADES) || (card > CLUBS)){
        card = UNKNOWN_SUIT;
    }

    if (card < 7) {
        do_something(card);
    }
}

Тип suit перечисляется с пятью опциями. Однако условное выражение card < 7 всегда рассчитывает значение true, потому что card может быть самое большее 5. The if оператор не нужен.

Коррекция 1 - Изменение условия

Одной из возможных коррекций является изменение условия if в коде. В этой коррекции значение 7 изменяется на UNKNOWN_SUIT непосредственно относиться к типу card.

typedef enum _suit {UNKNOWN_SUIT, SPADES, HEARTS, DIAMONDS, CLUBS} suit;
suit nextcard(void);
void do_something(suit s);

void bridge(void)
{
    suit card = nextcard();
    if ((card < SPADES) || (card > CLUBS)){
        card = UNKNOWN_SUIT;
    }

    if (card > UNKNOWN_SUIT) {
        do_something(card);
    }
}
Коррекция - Удалить, если

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

typedef enum _suit {UNKNOWN_SUIT, SPADES, HEARTS, DIAMONDS, CLUBS} suit;
suit nextcard(void);
void do_something(suit s);

void bridge(void)
{
    suit card = nextcard();
    if ((card < SPADES) || (card > CLUBS)){
        card = UNKNOWN_SUIT;
    }

    do_something(card);
}
Проблема

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

Например, вы записываете значение в переменную и затем записываете второе значение перед чтением предыдущего значения. Первая операция записи является избыточной.

Риск

Избыточные операции записи часто указывают на ошибки программирования. Например, вы забыли считать переменную между двумя последовательными операциями записи или непреднамеренно считать другую переменную.

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

Укажите причину записи в переменную, но не считывайте ее позже. Проверьте распространенные ошибки программирования, такие как случайное чтение другой переменной с подобным именем.

Если вы определяете, что операция записи избыточна, удалите операцию.

Пример - Запись без дальнейшей ошибки чтения
void sensor_amplification(void)
{
    extern int getsensor(void);
    int level;

    level = 4 * getsensor();            
    /* Defect: Useless write */
}

После переменной level присваивается значение 4 * getsensor(), он не читается.

Коррекция - Использование значения после присвоения

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

#include <stdio.h>

void sensor_amplification(void)
{
    extern int getsensor(void);
    int level;

    level = 4 * getsensor(); 
    
    /* Fix: Use level after assignment */
    printf("The value is %d", level);
    
}

Переменная level печатается, считывая новое значение.

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

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

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

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