Институт системного программирования им. В.П. Иванникова РАН


Безопасный компилятор

Безопасный компилятор предотвращает появление уязвимостей в программе при выполнении агрессивных оптимизаций кода (например, в результате использования конструкций, проявляющих неопределённое поведение). Минимально ограничивает выполняемые оптимизации, что позволяет избежать значительного падения производительности по сравнению с полным отключением оптимизаций.

Особенности и преимущества

Безопасный компилятор разработан на основе промышленного компилятора GCC и может быть использован в качестве его замены (например, при сборке дистрибутива ОС на базе Linux). Сохраняет эффективность генерируемого кода и даёт готовую безопасную сборку ПО.

Безопасный компилятор – это:

  • Доработанные оптимизации компилятора для консервативной обработки конструкций с неопределённым поведением и безопасного доопределения семантики программы.
  • Принудительная инициализация неинициализированных автоматических переменных.
  • Выдача предупреждений компиляции при обнаружении конструкций с неопределенным поведением.
  • Добавление динамических проверок для отдельных классов конструкций в целях исключения появления неопределённого поведения по время работы программы.
  • Диверсификация генерируемого кода во время выполнения программы.
  • Отсутствие необходимости модифицировать исходный код и файлы системы сборки, что позволяет максимально упростить пользование компилятором.
  • Распределение функций безопасности по трём классам, определяющим компромисс между безопасностью генерируемого кода и его производительностью. Самый низкий класс – III, самый высокий – I.

Безопасный компилятор осуществляет следующие действия:

Согласно III классу:

  • Предотвращение возникновения целочисленного переполнения, доступа к объектам через указатель несовместимого типа, разыменования нулевого указателя, замены функций ввода/вывода и работы с памятью стандартной библиотеки на эквивалентные машинные инструкции.
  • Обнаружение деления на ноль, некорректности битовых сдвигов, выхода за границы кадра стека, операций загрузки и/или записи в массив за пределами выделенной для него памяти. Обнаружение переменных автоматического класса памяти, которые хранятся на машинном регистре при вызове функций.

Согласно II классу:

  • Анализ аргументов битовых сдвигов; избыточности операций работы с памятью; выравнивания данных при работе с векторными инструкциями; адресной арифметики при оптимизациях, связанных с изменением порядка операций обращения к памяти.
  • Инициализация не инициализированных явно переменных автоматического класса памяти нулевыми значениями.
  • Остановка процесса трансляции при выдаче определённых предупреждений.

Согласно I классу:

  • Выполнение уникального распределения в памяти машинного кода функций в процессе динамической компоновки программы или при выполнении статической компиляции.
  • Добавление в программу машинного кода, вызывающего её аварийный останов при обнаружении ситуаций с неопределённым поведением во время выполнения программы:

    1) Операции с целыми или вещественными типами:

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

    2) Операции с указателями и массивами:

    • загрузка или запись по некорректно выравненному или нулевому указателю;
    • загрузка или запись в массив по адресу, находящемуся за пределами выделенной для него памяти;
    • передача нулевого указателя в качестве параметра функции, помеченного атрибутом nonnull;
    • выполнение операции адресной арифметики, приводящей к целочисленному переполнению;
    • возврат нулевого значения из функции, объявление которой содержит атрибут returns_nonnull;
    • выделение в автоматической памяти массива переменной длины с некорректным размером.

    3) Операции с функциями:

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

Для кого предназначен Безопасный компилятор?

  • Разработчики ОС.
  • Компании, разрабатывающие ПО с высокой степенью надёжности и безопасности.

Опыт внедрения

Безопасный компилятор поставляется в ряд российских компаний и организаций в дополнение к комплексу ИСП Crusher.

Поддерживаемые ОС

ОС семейства Linux x86 (32/64), armv7; Windows (mingw).

Разработчик/участник

Компиляторные технологии

Перейти к списку всех технологий