Что делает стандартную библиотечную функцию C опасной, и какова альтернатива?

В как можно меньшем количестве слов:

  • управляемый код = программы.NET
  • неуправляемый код = "нормальные" программы
66
задан 5 revs, 3 users 100% 20 May 2019 в 13:26
поделиться

9 ответов

Раньше у большинства строковых функций не было проверки границ. Конечно, они не могли просто удалить старые функции или изменить свои подписи, чтобы включить верхнюю границу, что нарушило бы совместимость. Теперь почти для каждой из этих функций есть альтернативная "n" версия. Например:

strcpy -> strncpy
strlen -> strnlen
strcmp -> strncmp
strcat -> strncat
strdup -> strndup
sprintf -> snprintf
wcscpy -> wcsncpy
wcslen -> wcsnlen

И др.

См. Также https://github.com/leafsr/gcc-poison , который представляет собой проект по созданию файла заголовка, который заставляет gcc сообщать об ошибке, если вы используете небезопасную функцию.

46
ответ дан 24 November 2019 в 14:58
поделиться

Да, fgets (..., ..., STDIN) - хорошая альтернатива gets () , потому что она требует размера параметр ( gets () фактически полностью удален из стандарта C в C11). Обратите внимание, что fgets () не совсем заменяет gets () , потому что первый будет включать завершающий символ \ n , если есть место в буфере для чтения всей строки.

scanf () в некоторых случаях считается проблематичным, а не просто «плохим», потому что, если ввод не соответствует ожидаемому формату, он может невозможно разумно восстановить (это не позволяет вам перемотать ввод и повторить попытку). Если вы можете просто отказаться от плохо отформатированного ввода, его можно использовать. Лучше" альтернативой здесь является использование функции ввода, такой как fgets () или fgetc () , для чтения фрагментов ввода, а затем сканирование их с помощью sscanf () или его синтаксический анализ с функциями обработки строк, такими как strchr () и strtol () . Также см. Ниже конкретную проблему со спецификатором преобразования "% s" в scanf () .

Это не стандартная функция C, а функция BSD и POSIX mktemp () , как правило, невозможно безопасно использовать, потому что всегда существует условие гонки TOCTTOU между проверкой существования файла и его последующим созданием. mkstemp () или tmpfile () - хорошие замены.

strncpy () - это немного сложная функция, потому что она не работает. t завершать назначение нулем, если для него не было места. Несмотря на явно общее название, эта функция была разработана для создания определенного стиля строки, который отличается от обычных строк C - строк, хранящихся в известном поле фиксированной ширины, где нулевой терминатор не требуется, если строка точно заполняет поле (исходный каталог UNIX записи были в этом стиле). Если у вас нет такой ситуации, вам, вероятно, следует избегать этой функции.

atoi () может быть плохим выбором в некоторых ситуациях, потому что вы не можете определить, когда произошла ошибка при преобразовании ( например, если число превышает диапазон int ). Используйте strtol () , если это важно для вас.

strcpy () , strcat () и sprintf () страдают от той же проблемы, что и gets () - они не позволяют указать размер целевого буфера. Все еще возможно, по крайней мере теоретически, безопасно использовать их, но вам намного лучше использовать вместо них strncat () и snprintf () (вы могли бы используйте strncpy () , но см. выше). Обратите внимание, что, в то время как n для snprintf () - это размер целевого буфера, n для strncat () - это максимальное количество добавляемых символов без нулевого терминатора. Другой альтернативой, если вы уже вычислили соответствующие размеры строки и буфера, является memmove () или memcpy () .

34
ответ дан 24 November 2019 в 14:58
поделиться

strtok () обычно считается злом, потому что он сохраняет информацию о состоянии между вызовами. Не пытайтесь запустить ЭТО в многопоточной среде!

20
ответ дан 24 November 2019 в 14:58
поделиться

Строго говоря, есть одна действительно опасная функция. Это gets () , потому что его ввод не контролируется программистом. Все остальные упомянутые здесь функции безопасны сами по себе. «Хорошее» и «плохое» сводятся к защитному программированию, а именно предварительным условиям, постусловиям и шаблонному коду.

Возьмем, к примеру, strcpy () . У него есть некоторые предварительные условия, которые программист должен выполнить перед вызовом функции. Обе строки должны быть действительными, ненулевыми указателями на строки с нулевым завершением, а место назначения должно предоставлять достаточно места с конечной длиной строки в диапазоне size_t . Кроме того, строки не могут перекрываться.

Это довольно много предварительных условий, и ни один из них не проверяется strcpy () . Программист должен быть уверен, что они выполняются, или он должен явно протестировать их с помощью дополнительного шаблонного кода перед вызовом strcpy () :

n = DST_BUFFER_SIZE;
if ((dst != NULL) && (src != NULL) && (strlen(dst)+strlen(src)+1 <= n))
{
    strcpy(dst, src);
}

Уже молчаливо предполагая неперекрывающиеся строки и строки с нулевым завершением.

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

strncpy(dst, src, n);
if (n > 0)
{
    dst[n-1] = '\0';
}

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

Или даже возразите против этого. Возьмем семейство printf () . Эти функции возвращают состояние, указывающее на ошибку и успех. Кто проверяет успешность вывода в stdout или stderr? С аргументом, что вы вообще ничего не можете сделать, когда стандартные каналы не работают. А как насчет спасения пользовательских данных и завершения программы с кодом выхода, указывающим на ошибку? Вместо возможной альтернативы сбоя и последующей записи с поврежденными пользовательскими данными.

В условиях ограниченных по времени и деньгам всегда возникает вопрос, сколько сетей безопасности вы действительно хотите и каков будет наихудший сценарий в результате? Если это переполнение буфера, как в случае с str-функциями, то имеет смысл запретить их и, вероятно, предоставить функции-обертки с уже существующими сетями безопасности.

И последний вопрос по этому поводу:

11
ответ дан 24 November 2019 в 14:58
поделиться

Любая функция, которая не принимает параметр максимальной длины и вместо этого полагается на присутствие маркера конца (например, многие функции обработки «строки»).

Любой метод, который поддерживает состояние между вызовами.

7
ответ дан 24 November 2019 в 14:58
поделиться

Просмотр страницы 7 (PDF-страница 9) Практики разработки SAFECode

Редактировать: Со страницы -

семейство strcpy
семейство strncpy
семья strcat
семья scanf
семья sprintf
получает семью

3
ответ дан 24 November 2019 в 14:58
поделиться

strcpy - снова!

Большинство людей согласны с тем, что strcpy опасен, но strncpy редко бывает полезной заменой. Обычно важно, чтобы вы знали, когда вам нужно обрезать строку в любом случае, и по этой причине вам обычно нужно всегда проверять длину исходной строки. Если это так, обычно memcpy является лучшей заменой, поскольку вы точно знаете, сколько символов вы хотите скопировать.

например, усечение является ошибкой:

n = strlen( src );

if( n >= buflen )
    return ERROR;

memcpy( dst, src, n + 1 );

усечение разрешено, но количество символов должно быть возвращено, чтобы вызывающий знал:

n = strlen( src );

if( n >= buflen )
    n = buflen - 1;

memcpy( dst, src, n );
dst[n] = '\0';

return n;
]
2
ответ дан 24 November 2019 в 14:58
поделиться
  • sprintf плохой, не проверяет размер, используйте snprintf
  • gmtime , localtime - используйте gmtime_r , localtime_r
6
ответ дан 24 November 2019 в 14:58
поделиться

Netbeans всегда был известен тем, что предоставлял поддержку экспериментальных (еще не выпущенных) технологий, таких как предварительная версия Java 6 EE, поддержка JDK7, ...

И поддержка подрывной деятельности из коробки. Это большое отличие от Eclipse, где вам нужно использовать плагины. С Eclipse у меня были проблемы только под Linux (проблемы с JavaHL, блабла ...). Я не помню, кто это сказал и где это написано, но "

4
ответ дан 24 November 2019 в 14:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: