CERT C: Rec. EXP08-C

Гарантируйте, что адресная арифметика с указателями используется правильно

Описание

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

Гарантируйте, что адресная арифметика с указателями используется правильно. [1]

Примеры

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

Описание

Эта проблема происходит, когда указатель, следующий из арифметики на операнде указателя, указывает на элемент вне массива того операнда указателя.

Риск

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

Стандарт C задает создание указателя на один вне конца массива. Правило разрешает Стандарт C. Разыменование указателя на один вне конца массива вызывает неопределенное поведение и несовместимо.

Описание

Это правило повышено каждый раз, когда анализ обнаруживает Subtraction or comparison between pointers to different arrays.

Риск

Это правило применяется к выражениям формы pointer_expression1 - pointer_expression2. Поведение не определено если pointer_expression1 и pointer_expression2:

  • Не указывайте на элементы того же массива,

  • Или не указывайте на элемент один вне конца массива.

Пример - вычитание указателей

#include <stddef.h>

void f1 (int32_t *ptr)
{
    int32_t a1[10];
    int32_t a2[10];
    int32_t *p1 = &a1[ 1];
    int32_t *p2 = &a2[10];
    ptrdiff_t diff1, diff2, diff3;

    diff1 =  p1 - a1;   // Compliant
    diff2 =  p2 - a2;   // Compliant
    diff3 =  p1 - p2;   // Non-compliant
}

В этом примере три выражения вычитания показывают различие между совместимыми и несовместимыми вычитаниями указателя. diff1 и вычитания diff2 совместимы, потому что указатели указывают на тот же массив. Вычитание diff3 несовместимо, потому что p1 и p2 указывают на различные массивы.

Описание

Неправильное масштабирование указателя происходит, когда Polyspace® Bug Finder™ полагает, что вы игнорируете неявное масштабирование в адресной арифметике с указателями.

Например, дефект может произойти в следующих ситуациях.

СитуацияРискВозможная фиксация
Вы используете оператор sizeof в арифметических операциях на указателе.

Оператор sizeof возвращает размер типа данных в количестве байтов.

Адресная арифметика с указателями уже неявно масштабируется размером типа данных резкой переменной. Поэтому использование sizeof в адресной арифметике с указателями приводит к непреднамеренным результатам.

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

Фиксация

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

Смотрите примеры мер ниже.

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

Пример - использование оператора sizeof

void func(void) {
    int arr[5] = {1,2,3,4,5};
    int *ptr = arr;

    int value_in_position_2 = *(ptr + 2*(sizeof(int)));
}

В этом примере операция 2*(sizeof(int)) возвращает дважды размер переменной int в байтах. Однако, потому что адресная арифметика с указателями неявно масштабируется, количеством байтов, которыми смещается ptr, является 2*(sizeof(int))*(sizeof(int)).

В этом примере неправильное масштабирование переключает ptr вне границ массива. Поэтому ошибка Pointer access out of bounds появляется на операции *.

Исправление — удаляет оператор sizeof

Одно возможное исправление должно удалить оператор sizeof.

void func(void) {
    int arr[5] = {1,2,3,4,5};
    int *ptr = arr;

    int value_in_position_2 = *(ptr + 2);
}

Пример - бросок после адресной арифметики с указателями

int func(void) {
    int x = 0;
    char r = *(char *)(&x + 1);
    return r;
}

В этом примере операция &x + 1 смещает &x sizeof(int). После операции получившийся указатель указывает вне позволенного буфера. Когда вы разыменовываете указатель, ошибка Pointer access out of bounds появляется на операции *.

Исправление — применяет бросок перед адресной арифметикой с указателями

Если вы хотите получить доступ к второму байту x, сначала бросьте &x к указателю char* и затем выполните адресную арифметику с указателями. Получившийся указатель смещается байтами sizeof(char) и неподвижными точками в позволенном буфере, размер которого является байтами sizeof(int).

int func(void) {
    int x = 0;
    char r = *((char *)(&x )+ 1);
    return r;
}

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

Группа: Rec. 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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

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