"Плохие" функции C против их" хороших " альтернатив



каковы "плохие" функции в C, и каковы их "хорошие" альтернативы?



Почему плохие плохие, и что делает хороших людей лучше?



Я знаю, например, gets() "плохо", потому что он не имеет никакой формы проверки границ. Какова его лучшая альтернатива? fgets()?



Я слышал scanf() - это плохо, но я не могу вспомнить, почему. Кто-нибудь знает? Какая самая лучшая альтернатива?



есть еще?

536   13  

13 ответов:

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

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

и многое другое.

изменить 2013-12-03:

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

да, fgets (,, STDIN) является хорошей альтернативой gets (), потому что он принимает параметр размера.

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

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

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

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

strcpy (), strcat() и sprintf () страдают от аналогичной проблемы с gets () - они не позволяют указать размер целевого буфера. Это еще возможно, по крайней мере в теории, чтобы использовать их безопасно - но вы много лучше использовать strncat() и snprintf () вместо этого (вы можете использовать strncpy (), но см. выше). В той же теме, Если вы используете семейство функций scanf (), не используйте простой "%s " - укажите размер пункта назначения, например. "%200s".

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

строго говоря, есть одна очень опасная функция. Это 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] = '';
}

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

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

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

один последний вопрос об этом: что делает вас уверенным, что ваши" хорошие " альтернативы действительно хороший?

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

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

  • sprintf Это плохо, не проверяет размер, используйте snprintf
  • gmtime,localtime--use gmtime_r,localtime_r

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

char buff[1000];
strncpy(buff, "1", sizeof buff);

скопирует 1 символ и перезапишет 999 байт с 0

еще одна причина, по которой я предпочитаю strlcpy (я знаю, что strlcpy-это BSDism, но его так легко реализовать, что нет никакого оправдания, чтобы не использовать его).

scanf() плохо, потому что это не предотвращает переполнение буфера. Я только недавно узнал об этом.

просмотр страницы 7 (PDF Страница 9) SAFECode Dev Practices

изменить: со страницы -

семейство strcpy
семья strncpy
функции strcat семьи
семейства scanf
sprintf family
получает семья

strcpy - опять!

большинство людей согласны с тем, что strcpy опасен, но strncpy редко бывает полезной заменой. Обычно важно, чтобы вы знали, когда вам нужно усечь строку в любом случае, и по этой причине вам обычно нужно изучить длину исходной строки anwyay. Если это так, обычно 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] = '';

return n;

Я бы сказал, что scanf Это хорошо иногда, более конкретно, когда вам действительно нужно что-то быстро прочитать. Это величины быстрее, чем cin

Я вспоминаю задание на международной олимпиаде по информатике (IOI), где нужно было использовать scanf с cin прошло слишком много времени.

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

Бах... Вафли. Эти функции небезопасны, потому что программисты-костяные головы. Что в этом плохого?

char msg[100] = {''};
int num = 10; //obtain num however
sprintf(msg, "There are %d items for sale", num);

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

Comments

    Ничего не найдено.