Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
>
>
>
Выход за границу массива

Выход за границу массива

06 Мар 2013

Выход за границу массива (Array index out of bounds) — это частный случай переполнения буфера. Ошибка возникает, если индекс, с помощью которого обращаются к элементам массива, превышает допустимое значение. При этом идёт обращение за границы массива, что является неопределенным поведением. Это возможно из-за того, что в языках программирования С и С++ нет строгого контроля выхода за границы массива: наличие проверок зависит от используемых инструментов и их реализации.

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

Рассмотрим данную ошибку на примерах, найденных в коде реальных Open Source проектов с помощью статического анализатора PVS-Studio.

Проект Dumb (динамическая универсальная музыкальная библиотека):

struct IT_SAMPLE
{
  ....
  unsigned char filename[14];
  ....
};

static int it_riff_dsmf_process_sample(
  IT_SAMPLE * sample, const unsigned char * data, int len)
{
  int flags;
  memcpy( sample->filename, data, 13 );
  sample->filename[ 14 ] = 0;
  ....
}

Массив filename состоит из 14 элементов, однако в функции it_riff_dsmf_process_sample идёт обращение к 14-му элементу, который находится за границами массива. Такую ошибку часто допускают, забывая, что индексация массивов в языках С и С++ начинается с нуля и заканчивается значением на единицу меньше размера массива (в данном случае — 13).

Рассмотрим ещё одну подобную ошибку. Проект Wolfenstein 3D (компьютерная игра, разработанная компанией id Software):

typedef struct bot_state_s
{
  ...
  char teamleader[32]; //netname of the team leader
  ...
}  bot_state_t;

void BotMatch_StartTeamLeaderShip(
  bot_state_t *bs, bot_match_t *match)
{
  ...
  bs->teamleader[sizeof( bs->teamleader )] = '\0';  //< =
  ...
}

В данном случае ошибка заключается в том, что sizeof(Array) вернёт размер массива, а для обращения к последнему элементу следует вычесть единицу из результата sizeof(Array).

Также здесь стоит сделать ремарку, что выбранный разработчиками способ доступа к последнему элементу не является надежным, т.к. работает только если массив содержит элементы размером 1 байт (char, unsigned char и т.п.). Более правильный способ получения индекса последнего элемента выглядит так:

const size_t lastPos = sizeof(bs->teamleader) / 
                       sizeof(bs->teamleader[0]) - 1;
bs->teamleader[lastPos] = '\0';

Здесь мы получаем общий размер массива в байтах и делим его на размер первого элемента, тем самым получая количество элементов в массиве. В конце остаётся только вычесть единицу. Полученное значение и будет индексом последнего элемента в массиве.

На самом деле, даже указанное выше исправление не является хорошим. Если вы пишите именно на С++, то для вас существуют более безопасные и удобные способы работы с массивами. Подробнее мы рассмотрели их в статье "Как не надо проверять размер массива в С++", а именно в разделе "Современный C++: правильное вычисление количества элементов в массивах и контейнерах".

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

Популярные статьи по теме


Комментарии (0)

Следующие комментарии next comments
close comment form
close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам