Данное диагностическое правило основано на руководстве MISRA (Motor Industry Software Reliability Association) по разработке программного обеспечения.
Это правило актуально только для C. Если в программе возникает неопределённое поведение, то у программиста нет никаких гарантий относительно её исполнения. Такое поведение недопустимо.
Если в программе возникает критическое неуточнённое поведение, это означает, что в зависимости от компилятора и его конфигурации возможно различное исполнение кода. Такое поведение также недопустимо.
В общем случае нельзя сказать, может ли в программе произойти неопределённое или неуточнённое поведение или нет. Не все случаи неопределённого поведения можно распознать. Поэтому нет и не может быть алгоритма, который гарантировал бы отсутствие неопределённого или неуточнённого поведения в конкретной программе.
Однако существует множество ситуаций, которые могут привести к неопределённому или критическому неуточнённому поведению и которые можно распознать алгоритмически. Рассмотрим некоторые из таких случаев.
Часто можно определить потенциальное разыменование нулевого указателя. Рассмотрим следующий фрагмент кода:
void foo()
{
int len = GetLen();
char *str = (char *) malloc(mlen + 1);
str[len] = '\0';
}
При выполнении этого фрагмента кода может произойти разыменование нулевого указателя. Если функция 'malloc' не сможет выделить память, то она запишет 'nullptr' в переменную 'str'. Тогда в выражении 'str[len]' произойдет разыменование 'nullptr', что является неопределенным поведением. Анализатор выдаст следующее предупреждение:
V2609 Undefined behaviour should not occur. There might be dereferencing of a potential null pointer 'str'. Check lines: 4, 5.
На первый взгляд может показаться, что подобные ошибки сразу приведут к аварийному завершению программы. Во многих операционных системах первые килобайты адресного пространства защищены от записи. И при попытке записи в них возникнет исключение/сигнал. А значит, ошибка не является критичной. Это совсем не так.
Более подробно все это рассмотрено в статье "Почему важно проверять, что вернула функция malloc".
Еще одной ситуацией, которую можно распознать алгоритмически, является модификация переменной между двумя точками следования и неоднократное обращение к ней.
Рассмотрим следующий фрагмент кода:
void foo()
{
int *ptr;
....
*ptr++ = *(ptr + 1);
}
Здесь предполагается, что сначала произойдет увеличение указателя 'ptr' на 1. Затем произойдет вычисление выражения 'ptr + 1', и использоваться будет уже новое значение 'ptr'.
Однако такое предположение программиста неверно. Дело в том, что между двумя точками следования происходит два обращения к переменной 'ptr', одно из которых модифицирует ее значение. В таком случае поведение программы неопределенное.
Анализатор выдаст следующее предупреждение:
V2609 Undefined behaviour should not occur. The 'bufl' variable is modified while being used twice between sequence points.
Также можно определить некорректное использование битовых операторов сдвига. Рассмотрим следующий код:
void foo()
{
int delta = -2;
....
int expr = DoSomeCalculations();
expr <<= delta;
}
Здесь переменная 'expr' сдвигается влево на -2 бита. Сдвиг на отрицательное число битов является некорректной операцией и приводит к неопределенному поведению.
Данная диагностика классифицируется как:
|