В компьютерном программировании проверка границ — это любой метод определения, находится ли переменная в пределах некоторых границ , прежде чем она будет использована. Обычно она используется для того, чтобы убедиться, что число соответствует заданному типу (проверка диапазона) или что переменная, используемая в качестве индекса массива, находится в пределах границ массива (проверка индекса). Неудачная проверка границ обычно приводит к генерации некоторого рода сигнала исключения .
Поскольку выполнение проверки границ во время каждого использования может быть трудоемким, это не всегда делается. Устранение проверки границ — это метод оптимизации компилятора , который устраняет ненужную проверку границ.
Проверка диапазона — это проверка, позволяющая убедиться, что число находится в определенном диапазоне; например, чтобы убедиться, что значение, которое будет присвоено 16-битному целому числу, находится в пределах емкости 16-битного целого числа (т. е. проверка на перенос ). Это не совсем то же самое, что проверка типа . [ как? ] Другие проверки диапазона могут быть более строгими; например, переменная для хранения номера календарного месяца может быть объявлена принимающей только диапазон от 1 до 12.
Проверка индекса означает, что во всех выражениях, индексирующих массив, значение индекса проверяется на соответствие границам массива (которые были установлены при определении массива), и если индекс выходит за пределы границ, дальнейшее выполнение приостанавливается из-за какой-либо ошибки. Поскольку чтение или, особенно, запись значения за пределами границ массива может привести к сбою программы или ее сбою или сделать уязвимыми местами безопасности (см. переполнение буфера ), проверка индекса является частью многих языков высокого уровня .
Ранние компилируемые языки программирования с возможностью проверки индекса включали ALGOL 60 , ALGOL 68 и Pascal , а также интерпретируемые языки программирования, такие как BASIC .
Многие языки программирования, такие как C , никогда не выполняют автоматическую проверку границ для повышения скорости. Однако это оставляет много ошибок выхода за пределы на единицу и переполнений буфера необнаруженными. Многие программисты считают, что эти языки жертвуют слишком многим ради быстрого выполнения. [1] В своей лекции на премии Тьюринга 1980 года К. А. Хоар описал свой опыт в разработке ALGOL 60 , языка, который включал проверку границ, сказав:
Следствием этого принципа является то, что каждое появление каждого индекса каждой индексированной переменной в каждом случае проверялось во время выполнения как по верхней, так и по нижней объявленным границам массива. Много лет спустя мы спросили наших клиентов, хотят ли они, чтобы мы предоставили возможность отключить эти проверки в интересах эффективности на производственных прогонах. Они единогласно настоятельно просили нас этого не делать — они уже знали, как часто ошибки индексации происходят на производственных прогонах, где их неспособность обнаружить может иметь катастрофические последствия. Я со страхом и ужасом отмечаю, что даже в 1980 году разработчики и пользователи языка не усвоили этот урок. В любой уважающей себя отрасли инженерии несоблюдение таких элементарных мер предосторожности давно бы противозаконно.
Основные языки, которые обеспечивают проверку во время выполнения, включают Ada , C# , Haskell , Java , JavaScript , Lisp , PHP , Python , Ruby , Rust и Visual Basic . В языках D и OCaml есть проверка границ во время выполнения, которая включается или отключается с помощью переключателя компилятора. В C++ проверка во время выполнения не является частью языка, но частью STL и включается с помощью переключателя компилятора (_GLIBCXX_DEBUG=1 или _LIBCPP_DEBUG=1). C# также поддерживает небезопасные области : разделы кода, которые (помимо прочего) временно приостанавливают проверку границ для повышения эффективности. Они полезны для ускорения небольших критических по времени узких мест, не жертвуя безопасностью всей программы.
Язык программирования JS ++ способен анализировать, находится ли индекс массива или ключ карты за пределами границ во время компиляции, используя существующие типы, которые являются номинальным типом, описывающим, находится ли индекс или ключ в пределах границ или за их пределами, и руководят генерацией кода. Было показано, что существующие типы добавляют всего 1 мс к времени компиляции. [2]
Безопасность, добавляемая проверкой границ, обязательно требует затрат процессорного времени, если проверка выполняется программно; однако, если проверки могут быть выполнены аппаратно, то безопасность может быть предоставлена «бесплатно» без затрат времени выполнения. Ранней системой с проверкой границ оборудования был мэйнфрейм серии ICL 2900, анонсированный в 1974 году. [3] Компьютер VAX имеет ассемблерную инструкцию INDEX для проверки индекса массива, которая принимает шесть операндов, все из которых могут использовать любой режим адресации VAX. Компьютеры B6500 и аналогичные им Burroughs выполняли проверку границ аппаратно, независимо от того, какой компьютерный язык был скомпилирован для создания машинного кода. Ограниченное количество более поздних процессоров имеют специализированные инструкции для проверки границ, например, инструкция CHK2 в серии Motorola 68000 .
Исследования ведутся по крайней мере с 2005 года относительно методов использования встроенного в x86 модуля управления виртуальной памятью для обеспечения безопасности доступа к массивам и буферам. [4] В 2015 году Intel предоставила свои расширения Intel MPX в архитектуре процессора Skylake , которая хранит границы в регистре ЦП и таблице в памяти. По состоянию на начало 2017 года по крайней мере GCC поддерживает расширения MPX.