LINUXTALKS.CO

На базе Clang для языка Си реализован режим проверки границ буферов

 , ,

L


0

1

Инженеры из компании Apple объявили о готовности для тестирования режима "-fbounds-safety" для компилятора Clang, предоставляющего гарантии безопасной работы с буферами в коде на языке Си. Режим включён в состав форка LLVM, поддерживаемого компанией Apple для проекта Swift. В дальнейшем запланирована постепенная передача функциональности "-fbounds-safety" в основную кодовую базу LLVM/Clang.

Отмечается, что предложенный механизм защиты уже активно применяется в продуктах Apple, таких как ядро XNU, прошивки, библиотеки для работы со звуком и декодировщики изображений. Включение режима "-fbounds-safety" снижает производительность приложений в среднем на 5% (разброс от -1% до 29%), увеличивает размер кода на 9.1% (разброс от -1.4% до 38%) и замедляет компиляцию на 11%.

Использование режима "-fbounds-safety" для автоматического выявления выхода за границы области памяти, связанной с указателем, требует добавления в код специальных аннотаций и включения заголовочного файла "ptrcheck.h". Суть предложенного метода защиты в автоматическом прикреплении проверок соблюдения допустимых границ, добавляемых на основе выставленных вручную аннотаций или известных компилятору размеров.

В отличие от использования в коде расширенных указателей (wide pointer), в которых кроме адреса имеются сведения о верхней и нижней границе буфера, использование режима "-fbounds-safety" не нарушает ABI (Application Binary Interface), не меняет формат экспортируемых указателей и не требует переработки сразу для всего проекта. В режиме "-fbounds-safety" расширенные указатели применяются только в областях, не пересекающихся с ABI, а для указателей, влияющих на ABI, применяются обычные указатели с подстановкой проверок, формируемых на основе аннотаций с информацией о границах.

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

Модель защиты на основе "-fbounds-safety" можно внедрять постепенно, файл за файлом, не прерывая разработку всего проекта. Добавление защиты в проект сводится к указанию аннотаций в определённом файле с кодом, устранению предупреждений компилятора и проведению тестирования работы программы, после чего данные этапы повторяются для следующего файла. Код с добавленными аннотациями остаётся совместим с обычным Си-кодом и компиляторами, не поддерживающими "-fbounds-safety" (при сборке другими компиляторами или при сборке без флага "-fbounds-safety" просто не будут добавлены дополнительные проверки границ).

Во время работы программы, в случае выявления обращения за пределы допустимых границ, генерируется исключение и программа завершает своё выполнение. Аварийное завершение также может произойти при указании некорректных аннотаций, поэтому при использовании "-fbounds-safety" необходимо проведение дополнительного тестирования работы программы.

В примере ниже в параметр "int *p" вставлена аннотация "__counted_by(n)", добавляющая дополнительную проверку на допустимые границы, действующую во время выполнения. Если попытаться скомпилировать код в режиме "-fbounds-safety" без указания данной аннотации, компилятор выведет предупреждение об отсутствии информации о границах массива при обработке выражения "p[i] = 0".

#include <ptrcheck.h>void init_buf(int *__counted_by(n) p, int n) {for (int i = 0; i < n; ++i)p[i] = 0; // в режиме «-fbounds-safety» компилятор сам подставит проверку, аналогичную коду «if (i < 0 || i >= n) trap();»}

Для локальных переменных с указателями проверки прикрепляются автоматически, например:

void foo(int i){char *buf = (char *)malloc(10); // для указателя buf будут сохранены сведения о границахbuf[i] = 0xff; // будет автоматически подставлена проверка «if (buf + i < buf || buf + i >= buf + 10) trap();»}

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

for (size_t i = 0; i < count; ++i) {buf[i] = i; // проверка «if (i < 0 || i >= count) trap()» добавлена не будет, так как выше уже имеется условие «i < count» и i не может быть меньше 0.}

Основные аннотации:

  • "__counted_by(N)" - определяет размер буфера в элементах целевого типа.
  • "__sized_by(N)" - определяет размер буфера в байтах.
  • " __ended_by(P)" - задаёт верхнюю границу буфера.
  • "__null_terminated" - учитывает нулевой символ в качестве конца буфера.
  • "__single" - привязывает указатель к одному объекту. Применяется по умолчанию для указателей, влияющих на ABI, если явно не выставлена аннотация.
  • "__bidi_indexable" - расширенный указатель с информацией о верхней и нижней границах. Применяется по умолчанию для указателей, не влияющих на ABI.
  • "__indexable" - расширенный указатель с информацией о верхней границе.
  • "__unsafe_indexable" - указатель без проверки границ (для переносимости с незащищённым кодом, например, для получения указателей из внешнего кода).

>>> Подробности

★★

Проверено: cocucka ()

«__sized_by(N)» - определяет размер буфера в байтах.

У тебя ошибка. Должно быть «размер буферов». И не в байтах, а в яблоках или апельсинах. Но лучше в дыньках.

Oberstserj    
★★★★★★
Последнее исправление: Oberstserj (всего исправлений: 1)

Ubuntu / Firefox (NL)
Ответ на: комментарий от MrSugoma

слыш, свинья, ты чего малыша обижаешь?:) и вещества верни обратно на полку. @Kaschenko видать пакеты с мивиной перепутал.


а кроме того, сосискин - мамкин пирожок и вахтер

crypt    
★★★☆☆
FreeBSD / Chrome (GB)
Ответ на: комментарий от cocucka

слыш, свинья, ты чего малыша обижаешь?:) и вещества верни обратно на полку. @Kaschenko видать пакеты с мивиной перепутал.


а кроме того, сосискин - мамкин пирожок и вахтер

crypt    
★★★☆☆
FreeBSD / Chrome (GB)
Ответ на: комментарий от MrSugoma

Знание года рождения — значительный этап на пути к деанону.

Чувак, сдеанонить тебя не самая большая проблема, учитывая количество твоих проебов в одной только этой ветке))

Oberstserj    
★★★★★★
Ubuntu / Firefox (NL)
Ответ на: комментарий от Oberstserj

учитывая количество твоих проебов в одной только этой ветке

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

MrSugoma    
★★
Windows / Firefox (NL)
Ответ на: комментарий от MrSugoma

Да и тем более, если меня сдеанонят, я не делаю ничего противозаконного, Россию люблю, в отличие от тебя.

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

Oberstserj    
★★★★★★
Ubuntu / Firefox (NL)