Не формируйте или используйте за пределы индексы массивов или указатели
Доступ к массиву за пределы происходит, когда индекс массива выходит за пределы области значений [0...array_size-1]
во время доступа к массиву.
Доступ к массиву вне его границ является неопределенным поведением. Можно считать непредсказуемое значение или попытку получить доступ к местоположению, которое не позволено, и столкнитесь с отказом сегментации.
Фиксация зависит от первопричины дефекта. Например, вы получили доступ к массиву в цикле, и одна из этих ситуаций произошла:
Верхняя граница цикла является слишком большой.
Вы использовали индекс массива, который совпадает с индексом цикла вместо того, чтобы быть тем меньше, чем индекс цикла.
Чтобы устранить проблему, необходимо изменить связанный цикл или индекс массива.
Другой причиной, почему индекс массива может превысить границы массивов, является предшествующее преобразование от со знаком до беззнакового целого. Преобразование может привести к тому, чтобы переносить индексного значения, в конечном счете заставив индекс массива превысить границы массивов.
Часто детали результата показывают последовательность событий, которые привели к дефекту. Можно реализовать закрепление на любом событии в последовательности. Если детали результата не показывают историю события, можно проследить использование, щелкните правой кнопкой по опциям по исходному коду и смотрите предыдущие связанные события. См. также Интерпретируют Результаты Polyspace Bug Finder.
Смотрите примеры мер ниже.
Если вы не хотите устранять проблему, добавьте комментарии в свой результат или код, чтобы избежать другого анализа. Смотрите Результаты Polyspace Адреса Через Исправления ошибок или Комментарии.
#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 Bug Finder.
Смотрите примеры мер ниже.
Если вы не хотите устранять проблему, добавьте комментарии в свой результат или код, чтобы избежать другого анализа. Смотрите Результаты Polyspace Адреса Через Исправления ошибок или Комментарии.
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
указывает вне блока памяти, присвоенного ему, это не разыменовывается больше.
Доступ к массиву с испорченным индексом обнаруживает чтение или запись в массив при помощи испорченного индекса, который не был подтвержден.
Индекс может быть вне допустимой области значений массивов. Если испорченный индекс вне области значений массивов, он может вызвать:
Недостаточное наполнение буфера / подписывает — пишущий в память перед началом буфера.
Переполнение буфера — пишущий в память после конца буфера.
Зачитываясь буфер — доступ к памяти после конца целенаправленного буфера.
Под чтением буфер или память доступа перед началом целенаправленного буфера.
Атакующий может использовать недопустимую операцию чтения, или операция записи создают к проблемам в вашей программе.
Перед использованием индекса, чтобы получить доступ к массиву, подтвердите индексное значение, чтобы убедиться, что это в области значений массивов.
#define SIZE100 100
extern int tab[SIZE100];
int taintedarrayindex(int num) {
return tab[num];
}
В этом примере индекс num
получает доступ к массиву tab
. Функция не проверяет, чтобы видеть, ли num
в области значений tab
.
Одно возможное исправление должно проверять, что num
находится в области значений перед использованием его.
#define SIZE100 100 extern int tab[SIZE100]; int taintedarrayindex(int num) { if (num >= 0 && num < SIZE100) { return tab[num]; } else { return -9999; } }
Использование испорченного дефекта указателя повышено когда:
Испорченный Нулевой указатель — указатель не подтвержден против NULL.
Испорченный указатель размера — размер зоны памяти, на которую указывает указатель, не подтвержден.
На одном указателе ваш код может иметь экземпляры Использования испорченного указателя, Указатель разыменовывают с испорченным смещением, и Испорченным NULL или не пустой отключенной строкой. Средство поиска ошибки повышает только первый испорченный дефект указателя, который оно находит.
Атакующий может дать вашей программе подсказку, которая указывает на неожиданные ячейки памяти. Если указатель разыменовывается, чтобы записать, атакующий может:
Измените переменные состояния критической программы.
Заставьте свою программу отказывать.
Выполните нежелательный код.
Если указатель разыменовывается, чтобы читать, атакующий может:
Считайте уязвимые данные.
Заставьте свою программу отказывать.
Измените переменную программы к неожиданному значению.
Избегайте использования указателей из внешних источников.
Также, если вы доверяете внешнему источнику, санируете указатель, прежде чем разыменуют. В отдельной функции санитизации:
Проверяйте, что указатель не является ПУСТЫМ.
Проверяйте размер ячейки памяти (если возможный). Эта вторая проверка подтверждает, ожидает ли размер данных, указатель указывает на соответствия размеру вашу программу.
Дефект все еще появляется в теле функции санитизации. Однако, если вы используете функцию санитизации вместо нескольких случаев, дефект появляется только однажды. Можно выровнять по ширине дефект и скрыть его в более поздних отзывах при помощи аннотаций кода. Смотрите Результаты Polyspace Адреса Через Исправления ошибок или Комментарии.
void taintedptr(int* p, int i) {
*p = i;
}
В этом примере указатель *p
передается в качестве аргумента, и значение изменяется. Указатель может быть пустым или указать на неизвестную память, которая может быть уязвимой.
Одно возможное исправление должно избежать указателей из внешних источников.
int *taintedptr(int i) { /* Use heap memory allocated in the application */ int *p = (int *)malloc(sizeof (int)); if (p != NULL) { /* Check for success */ *p = i; } return p; }
Другое возможное исправление должно санировать указатель перед использованием его. Этот пример использует вторую функцию, чтобы проверять, является ли указатель пустым и может быть разыменован.
#include <stdlib.h>
int* sanitize_ptr(int* p) {
int* res = NULL;
if (p && *p) { /* Tainted pointer detected here, used as "firewall" */
/* Pointer is not null and dereference ok */
res = p;
}
return res;
}
void taintedptr(int* p, int i) {
p = sanitize_ptr(p);
if (p) {
*p = i;
}
}
Указатель разыменовывает с испорченным смещением, обнаруживает разыменование указателя, или чтение или запись, с помощью переменной смещения из неизвестного или небезопасного источника.
Эта проверка фокусируется на динамически выделенных буферах. Для статических буферных смещений смотрите Array access with tainted index
.
Индекс может быть вне допустимой области значений массивов. Если испорченный индекс вне области значений массивов, он может вызвать:
Недостаточное наполнение буфера / подписывает, или пишущий в память перед началом буфера.
Переполнение буфера, или пишущий в память после конца буфера.
По чтению буфера или доступу к памяти после конца целенаправленного буфера.
Под чтением буфер или память доступа перед началом целенаправленного буфера.
Атакующий может использовать недопустимое чтение или записать, чтобы поставить под угрозу вашу программу.
Подтвердите индекс, прежде чем вы будете использовать переменную, чтобы получить доступ к указателю. Проверяйте, чтобы убедиться, что переменная в допустимой области значений и не переполняется.
#include <stdlib.h>
enum {
SIZE10 = 10,
SIZE100 = 100,
SIZE128 = 128
};
extern void read_pint(int*);
int taintedptroffset(int i) {
int* pint = (int*)calloc(SIZE10, sizeof(int));
int c = 0;
if(pint) {
/* Filling array */
read_pint(pint);
c = pint[i];
free(pint);
}
return c;
}
В этом примере функция инициализирует целочисленный указатель pint
. Указатель разыменовывается с помощью входного индекса i
. Значение i
могло быть вне области значений указателя, вызвав ошибку из области значений.
Одно возможное исправление должно подтвердить значение индекса. Если индекс в допустимой области значений, продолжите разыменование указателя.
#include <stdlib.h> enum { SIZE10 = 10, SIZE100 = 100, SIZE128 = 128 }; extern void read_pint(int*); int taintedptroffset(int i) { int* pint = (int*)calloc(SIZE10, sizeof(int)); int c = 0; if (pint) { /* Filling array */ read_pint(pint); if (i>0 && i<SIZE10) { c = pint[i]; } free(pint); } return c; }
Группа: 04. Контейнеры (CTR) |
[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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.
Это программное обеспечение и сопоставленная документация не были рассмотрены, ни являются подтвержденным Университетом Карнеги-Меллон или его Институтом программной инженерии.
1. Если смысл перевода понятен, то лучше оставьте как есть и не придирайтесь к словам, синонимам и тому подобному. О вкусах не спорим.
2. Не дополняйте перевод комментариями “от себя”. В исправлении не должно появляться дополнительных смыслов и комментариев, отсутствующих в оригинале. Такие правки не получится интегрировать в алгоритме автоматического перевода.
3. Сохраняйте структуру оригинального текста - например, не разбивайте одно предложение на два.
4. Не имеет смысла однотипное исправление перевода какого-то термина во всех предложениях. Исправляйте только в одном месте. Когда Вашу правку одобрят, это исправление будет алгоритмически распространено и на другие части документации.
5. По иным вопросам, например если надо исправить заблокированное для перевода слово, обратитесь к редакторам через форму технической поддержки.