Checked C — это расширение языка C, призванное сделать его более безопасным и надежным. Может ли это уменьшить количество уязвимостей в таком большом количестве системного программного обеспечения?
C по-прежнему остается важным языком. Он используется как в системном программном обеспечении высокого уровня, таком как операционные системы, так и в коде низкого уровня, используемом во встроенных процессорах. Причина, по которой это по-прежнему хороший выбор, в том, что он близок к оборудованию и эффективен. Конечно, любое приложение, которое не должно быть близко к оборудованию, лучше закодировать на более современном и более абстрактном языке, который защищает вас от ошибок, которые могут возникнуть в C, — если вы можете принять потенциально более низкий эффективность.
Все основные проблемы, возникающие при использовании C, связаны с его возможностями необработанного указателя. В C указатель — это тонко замаскированный машинный адрес, и поэтому вы можете использовать его для доступа к любой ячейке памяти. Обычно это причина использования C, но часто это происходит ужасно неправильно, когда хранимых данных больше, чем может вместить выделенная память. Эта ситуация вызывает опасное переполнение буфера, что может привести к сбою программы, сбоям системы или захвату машины злоумышленником.
Проблема в том, что язык C не проверяет, используете ли вы указатель в той области памяти, которую намеревались использовать. Checked C, как следует из названия, проверяет, находитесь ли вы в указанной области памяти.
Отмеченный C является расширением C, поэтому ваши существующие программы по-прежнему будут работать, но, конечно, вы не получите ничего нового, если не будете использовать новые типы указателей.
Есть три разных типа проверенных указателей:
Первый — это простой указатель, который не поддерживает арифметику указателей — он просто указывает на местоположение и перед использованием проверяется, чтобы убедиться, что он не равен нулю:
ptr
Большинство ошибок типа переполнения буфера возникают, когда для перемещения указателя используется арифметика указателей, но многие указатели используются таким образом, поэтому лучше сделать их безопасными и явно исключить их возможность арифметики указателей.
Второй — указатель на массив известного размера:
array_ptr
Это проверяется, чтобы убедиться, что он находится в пределах объявленных границ массива при его использовании. Это означает, что нет никаких шансов случайно прочитать или записать за пределами конца массива.
Третий — это обобщение второй и произвольной области памяти различного размера:
span
Границы области переносятся с помощью указателя и динамически регулируются. Указатель проверяется на предмет нахождения в границах и ненулевого значения каждый раз, когда он используется.
Кроме того, существуют типы проверенных массивов, которые соответствуют указателю на проверенный массив:
int a проверено [10];
Поэтому, если вы попытаетесь использовать [10], результатом будет ошибка времени выполнения.
Это все хорошая идея?
Это настолько хорошая идея, что очень трудно понять, почему она не была представлена в C раньше. Часто утверждают, что причина того, что C не проверял указатели раньше, заключается в том, что проверка требует времени, и решать, включать ли проверку границ или нет, остается программист. Конечно, если вы расширите C, чтобы включить указатели с проверкой границ, тогда программист может решить использовать или не использовать в зависимости от ситуации.
Другой вопрос — действительно ли нам нужны такого рода улучшения в языках?
IDE, такие как NetBeans, проводят тщательный анализ вашего кода и выявляют потенциальные проблемы. NetBeans будет отмечать гораздо более широкий круг проблем, чем просто трудности с указателем, включая такие вещи, как использование нулевого завершения строк в библиотечных функциях вместо использования более безопасных альтернатив.
Конечно, есть много программистов, которые отказываются от помощи IDE и предпочитают работать с минимальными инструментами. Компиляторы, такие как GCC и CLANG, на самом деле не изо всех сил стараются быть дружественными к IDE, что явно является старомодным подходом. Сравните это с позицией команды Microsoft C #, которая придерживается мнения, что компиляторы должны нацеливаться на инструменты, а не на машинный код — см. Андерс Хейлсберг — Создание компиляторов на современном пути.
Модификация C — неплохой путь, но улучшение инструментария и его фактическое использование — это еще один, и потенциально он гораздо более полезен.