exponenta event banner

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

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

Описание

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

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

Внедрение Polyspace

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

  • Доступ к массиву вне границ.

  • Доступ указателя выходит за границы.

  • Доступ к массиву с поврежденным индексом.

  • Отмена привязки указателя с запятнанным смещением.

Примеры

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

Проблема

Доступ к массиву вне границ происходит, когда индекс массива выходит за пределы диапазона [0...array_size-1] во время доступа к массиву.

Риск

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

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

Исправление зависит от первопричины дефекта. Например, вы получили доступ к массиву внутри цикла, и произошла одна из следующих ситуаций:

  • Верхняя граница цикла слишком велика.

  • Используется индекс массива, который совпадает с индексом цикла, а не на единицу меньше индекса цикла.

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

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

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

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

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

Пример - Ошибка доступа к массиву вне границ
#include <stdio.h>

void fibonacci(void)
{
    int i;
    int fib[10];
 
    for (i = 0; i < 10; i++) 
       {
        if (i < 2) 
            fib[i] = 1;
         else 
            fib[i] = fib[i-1] + fib[i-2];
       }

    printf("The 10-th Fibonacci number is %i .\n", fib[i]);   
    /* Defect: Value of i is greater than allowed value of 9 */
}

Множество fib назначается размер 10. Индекс массива для fib имеет допустимые значения [0,1,2,...,9]. Переменная i имеет значение 10, когда оно выходит из for-луп. Следовательно, printf оператор пытается получить доступ fib[10] через i.

Исправление - сохранение индекса массива в пределах массива

Одной из возможных корректировок является печать fib[i-1] вместо fib[i] после for-луп.

#include <stdio.h>

void fibonacci(void)
{
   int i;
   int fib[10];

   for (i = 0; i < 10; i++) 
    {
        if (i < 2) 
            fib[i] = 1;
        else 
            fib[i] = fib[i-1] + fib[i-2];
    }

    /* Fix: Print fib[9] instead of fib[10] */
    printf("The 10-th Fibonacci number is %i .\n", fib[i-1]); 
}

printf доступ к операторам fib[9] вместо fib[10].

Проблема

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

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

Риск

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

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

Исправление зависит от первопричины дефекта. Например, вы отменили ссылку на указатель внутри цикла, и произошла одна из следующих ситуаций:

  • Верхняя граница цикла слишком велика.

  • Для продвижения указателя с неправильным значением приращения указателя использовалась арифметика указателя.

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

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

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

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

Пример - Ошибка доступа указателя за пределами границ
int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
   {
    ptr++;
    *ptr=i;
    /* Defect: ptr out of bounds for i=9 */
   }

 return(arr);
}

ptr назначается адрес arr указывает на блок памяти размера 10*sizeof(int). В for-луп, ptr увеличивается в 10 раз. В последней итерации цикла ptr точки за пределами назначенного ему блока памяти. Поэтому его нельзя обособлять.

Коррекция - Проверка того, что указатель остается в пределах границ

Одной из возможных корректировок является изменение порядка приращения и отмены привязки ptr.

int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
     {
      /* Fix: Dereference pointer before increment */
      *ptr=i;
      ptr++;
     }

 return(arr);
}

После последнего приращения, хотя ptr точки за пределами назначенного ему блока памяти, больше он не обособлен.

Проблема

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

Риск

Возможно, индекс находится за пределами допустимого диапазона массива. Если запятнанный индекс находится вне диапазона массива, это может привести к следующему:

  • Underflow/underbrite буфера - запись в память перед началом буфера.

  • Переполнение буфера - запись в память после окончания буфера.

  • Перечитывание буфера - доступ к памяти после окончания целевого буфера.

  • Недостаточное чтение буфера или доступ к памяти перед началом целевого буфера.

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

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

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

Пример - Используйте индекс для возврата значения буфера
#include <stdlib.h>
#include <stdio.h>
#define SIZE100 100
extern int tab[SIZE100];
static int tainted_int_source(void) {
  return strtol(getenv("INDEX"),NULL,10);
}
int taintedarrayindex(void) {
	int num = tainted_int_source();
    return tab[num];  
}

В этом примере индекс num получает доступ к массиву tab. Функция не проверяет, num находится в диапазоне tab.

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

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

#include <stdlib.h>
#include <stdio.h>
#define SIZE100 100
extern int tab[SIZE100];
static int tainted_int_source(void) {
	return strtol(getenv("INDEX"),NULL,10);
}
int taintedarrayindex(void) {
	int num = tainted_int_source();
	if (num >= 0 && num < SIZE100) {
		return tab[num]; 
	} else {
		return -1;
	}
}

Проблема

Отмена привязки указателя с запятнанным смещением обнаруживает отмену привязки указателя, считывающего или записывающего, используя переменную смещения из неизвестного или небезопасного источника.

Эта проверка фокусируется на динамически назначаемых буферах. Для получения информации о смещениях статического буфера см. раздел Array access with tainted index.

Риск

Возможно, индекс находится за пределами допустимого диапазона массива. Если запятнанный индекс находится вне диапазона массива, это может привести к следующему:

  • Переполнение буфера/подзапись или запись в память перед началом буфера.

  • Переполнение буфера или запись в память после окончания буфера.

  • Чтение буфера или доступ к памяти после окончания целевого буфера.

  • Недостаточное чтение буфера или доступ к памяти перед началом целевого буфера.

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

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

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

Пример - массив указателей отмены привязки
#include <stdio.h>
#include <stdlib.h>
enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};
extern void read_pint(int*);

int taintedptroffset(void) {
    int offset;
    scanf("%d",&offset);
    int* pint = (int*)calloc(SIZE10, sizeof(int));
    int c = 0;
    if(pint) {
        /* Filling array */
        read_pint(pint);
        c = pint[offset];
        free(pint);
    }
    return c;
}

В этом примере функция инициализирует целочисленный указатель pint. Указатель обнуляется с помощью входного индекса offset. Значение offset может находиться вне диапазона указателей, что приводит к ошибке вне диапазона.

Коррекция - проверка индекса перед исключением

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

#include <stdlib.h>
#include <stdio.h>
enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};
extern void read_pint(int*);

int taintedptroffset(void) {
    int offset;
    scanf("%d",&offset);
    int* pint = (int*)calloc(SIZE10, sizeof(int));
    int c = 0;
    if (pint) {
        /* Filling array */
        read_pint(pint);
        if (offset>0 && offset<SIZE10) {
            c = pint[offset];
        }
        free(pint);
    }
    return c;
}

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

Группа: Правило 06. Массивы (ARR)
Представлен в R2019a

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

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

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