Это несколько распространенный вопрос для меня: как мы пишем C в загрязнение Чтобы сделать его безопасным и безопасным для миллиардов установок? Некоторые меры предосторожности, которые мы принимаем, и решения, которые мы принимаем. Там нет серебряной пули, только рекомендации. Как я думаю, вы можете увидеть сами ниже, они также не являются ни странными, ни удивительными.
«C» в Curl не и никогда не выступал за язык программирования C, это означает клиентПолем
Отказ от ответственности
Этот текст никоим образом не означает, что мы иногда не объединяем ошибки, связанные с безопасностью. Мы делаем. Мы люди. Мы делаем ошибки. Тогда мы исправим их.
Тестирование
Мы пишем как можно больше тестов. Мы запускаем все инструменты анализатора статического кода, которые мы можем на коде – часто. Мы запускаем Fuzzers на коде без перерыва.
C не безопасен для памяти
Мы, конечно, не застрахованы от ошибок, ошибок или уязвимостей, связанных с памятью. Мы считаем около 40% наших уязвимостей безопасности на сегодняшний день, чтобы они были прямым результатом, когда мы используем C вместо альтернативы, безопасной для памяти языка. Это, однако, гораздо меньше, чем 60-70%, которые обычно повторяются, происходящие из нескольких крупных компаний и проектов. Если это из -за разницы в подсчете или нас, на самом деле имея меньшее количество проблем C, я не могу сказать.
За последние пять лет мы получили нет Отчеты идентифицируют критический уязвимость, и только два из них были оценены при серьезности высокийПолем Остальные (60) были на серьезности низкий или серединаПолем
В настоящее время у нас есть около 180 000 строк производственного кода C89 (исключая пустые строки). Мы придерживаемся C89 для самой широкой переносимости и потому, что мы верим в непрерывную безостановочную итерационную и полировку и никогда не переписываем.
Читаемость
Код должен быть легко читать. Это должно быть ясно. Никаких скрытых кодов под умными конструкциями, модными макросами или перегрузкой. Легко для чтения код легко просмотреть, легко отлаживать и легко расширить.
Меньшие функции легче читать и понимать, чем более длинные, что предпочтительнее.
Код должен читать так, как если бы он был написан одним человеком. Должен быть последовательный и единый стиль кода на всем протяжении, так как это помогает нам лучше читать код. Неправильный или непоследовательный стиль кода – ошибка. Мы исправляем все ошибки, которые мы находим.
У нас есть инструменты, которые проверяют базовое соответствие стиля кода.
Узкий код и короткие имена
Код должен быть написан узким. На глазах сложно читать длинные линии, поэтому мы обеспечиваем строгую максимальную длину линии 80 столбцов. Мы используем два пространства, чтобы все еще позволить нам выполнить некоторое количество уровней отступа, прежде чем предел столбца станет проблемой. Если уровень отступления становится проблемой, возможно, его следует разделить на несколько подфункций?
Также связаны: (в частности, местные) Идентификаторы и имена должны быть короткими. Наличие длинных имен затрудняет их читать, особенно если есть несколько похожих. Не говоря уже о том, что они могут быть трудно вписаться в 80 столбцов после некоторого количества отступ.
Сейчас так много людей будут шутить и скажут что -то о доступных широких экранах, а что нет, но ключом здесь является читаемость. Более широкий код труднее читать. Период. Вопрос может заключаться в том, где нарисовать предел, и это дебаты для каждого проекта.
Без предупреждения
Хотя это уже должно быть естественным для всех, мы, конечно, строим весь код завивки, без какого -либо предупреждения компилятора ни в одной из 220+ рабочих мест, которые мы выполняем. Мы строим курль со всеми самыми придирчивыми вариантами компилятора, которые существуют с набором компиляторов, которые мы используем, и мы замолчаем каждое предупреждение, которое появляется. Мы рассматриваем каждое предупреждение компилятора как ошибку.
Избегайте «плохих» функций
Есть некоторые функции C, которые просто плохие из -за отсутствия граничного контроля или местного состояния, и мы избегаем их (Get, Sprintf, Strcat, Strtok, Localtime и т. Д.).
Есть некоторые функции C, которые сложны другими способами. У них слишком открытая функциональность или делает вещи, которые часто оказываются проблематичными или просто неправильными; Они легко приводят нас к ошибкам. Мы избегаем SSCANF и STRNCPY по этим причинам.
У нас есть инструменты, которые запретить Использование этих функций в нашем коде. Попытка ввести использование одного из них в запросе на привлечение заставляет задания CI покраснеть и предупредить автора об их ошибке.
Буферные функции
Несколько лет назад мы обнаружили, что сделали несколько ошибок в коде, которые имели дело с различными динамическими буферами. У нас было слишком много отдельных реализаций, работающих над динамически растущими областями памяти. Мы объединили эту обработку с новым набором внутренних справочных функций для растущих буферов, и теперь убедились, что мы используем только их. Это резко уменьшает потребность в Realloc (), что помогает нам избежать ошибок, связанных с этой функцией.
Каждый динамический буфер также имеет свой собственный набор максимальных размеров, который в его простоте также помогает поймать ошибки. В текущем коде libcurl у нас есть 80 чего -то другого динамические буферыПолем
Функции анализа
Я упомянул, как нам не нравится SSCANF. Это мощная функция для анализа, но он часто заканчивается тем, что анализ больше, чем то, что пользователь хочет (например, более одного места, даже если только одно должно быть принято), и он имеет слабую (несуществующую) обработку целочисленного переполнения. Наконец, он приводит пользователей в копирование проанализированных результатов вокруг излишне, что приводит к лишним использованию локальных буферов стека или недолговечным распределениям кучи.
Вместо этого мы представили еще один набор вспомогательных функций для анализа строки, и со временем мы переключаем весь код анализатора в сгибании на использование этого набора. Это облегчает писать строгие анализаторы, которые соответствуют именно тем, что мы хотим, чтобы они соответствовали, избегали дополнительных копий/маллоков, и это лучше проведено строгим целым числом, а границ проверяет.
Мониторинг функции памяти Использование
Проблемы с памятью часто включают динамическое распределение памяти с последующей копией данных в распределенную область памяти. Или, возможно, если распределение и копия выполняются правильно, нет проблем, но если какие -либо из них неверны, могут стать плохими. Поэтому мы стремимся к минимуму этой модели. Мы скорее предпочитаем Strdup и дубликацию памяти, которые выделяют и копируют данные в одном и том же вызове – или использование вспомогательных функций, которые могут делать эти вещи за их API. Мы запускаем ежедневный обновленный график на приборной панели Curl, который показывает плотность вызова функции памяти в Curl. В идеале этот сюжет будет продолжать падать со временем.
Возможно, можно также добавить, что мы избегаем лишних распределений памяти, в частности на горячих путях. Большая загрузка не требует больше ассигнований, чем маленькая.
Умножения с двойной проверкой
Целое число переполнений – еще одна область для беспокойства. Каждая сделанная арифметическая операция должна быть сделана с уверенностью, что она не переполняется. К сожалению, это все еще в основном ручной труд, оставленный для обнаружения человеческих обзоров.
64-битная поддержка гарантированная
В начале 2023 года мы отказались от поддержки сгибания на строительстве на системах без функционального 64-битного целочисленного типа. Это упрощает много кода и логики. Целочисленные переполнения с меньшей вероятностью будут вызывать, и нет никакого риска, что авторы случайно считают, что они делают 64-битную арифметику, в то время как это может оказаться 32-разрядным в некоторых редких сборках, которые могут произойти в прошлом. Переполнение и ошибки все еще могут произойти, если использовать неправильный тип, конечно.
Максимальная длина строки
Чтобы помочь нам избежать ошибок на строках, в частности с целочисленным переполнением, но также и с другой логикой, мы имеем общую проверку всех входов строк в библиотеку: они не принимают строки дольше, чем установленное ограничение. Мы считаем, что любая строка, которая длиннее, является либо просто вопиющей ошибкой, либо какой -то попытки (атака?), Чтобы вызвать что -то странное в библиотеке. Мы возвращаем ошибку при таких вызовах. Этот максимальный предел сейчас составляет восемь мегабайтов, но мы могли бы скорректировать это в будущем по мере развития мира и сгиба.
Держите Мастер Золотого
Ни в коем случае не разрешается разорвать мастер. Мы только объединяем код в Мастер, который, по нашему мнению, чистый, прекрасный и прекрасно работает. Это все еще терпит неудачу в момент времени, но затем мы делаем все возможное, чтобы решить ситуацию как можно быстрее.
Всегда проверяйте и действуйте по ошибкам
В сгибании мы всегда проверяем ошибки и выручим без утечки памяти Если (когда!) Они случаются. Это включает в себя все операции памяти, ввод -вывод, файловые операции и многое другое. Все звонки.
Некоторые разработчики привыкли к современным операционным системам, в основном не могут вернуть ошибку для некоторых из них, но Curl работает во многих средах с различным поведением. Кроме того, системная библиотека не может Выход или прервать При ошибках необходимо позволить заявлению принять это решение.
APIS и ABIS
Каждая функция и интерфейс, который общедоступный должен никогда измениться таким образом, что рискует сломать API или ABI. По этой причине и облегчить обнаружение функций, которые нуждаются в этих дополнительных мер предосторожности, у нас есть строгий правило: публичные функции префикс «curl_», и никакие другие функции не используют этот префикс.
Каждый может сделать это
Благодаря процессу человеческих рецензентов, множеству автоматических инструментов и сложного и обширного набора тестов, каждый может (попытаться) написать код завивки. Предполагая, что вы знаете C, конечно. Риск того, что что -то плохое пойдет на незамеченное, примерно равен, независимо от того, кто автор Кодекса. Ответственность разделяется.
Вперед, продолжать. Вы можете сделать это!
2025-04-07 06:51:00
1744017188
#Написание #для #curl #daniel.haxx.se
Продолжение темы
