Sscanf считается безопасным для использования? - PullRequest
15 голосов
/ 03 мая 2011

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

Ответы [ 6 ]

8 голосов
/ 03 мая 2011

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


Редактировать

Это не всегда безопасно для сканирования строк.

Если ваш размер буфера является постоянным, то вы, безусловно, можете указать его как %20s. Но если это не константа, вам нужно указать ее в строке формата, и вам нужно будет сделать:

char format[80]; //Make sure this is big enough... kinda painful
sprintf(format, "%%%ds", cchBuffer - 1); //Don't miss the percent signs and - 1!
sscanf(format, input); //Good luck

, что возможно, но очень легко ошибиться, как я делал в моем предыдущем редактировании (забыл позаботиться о нулевом терминаторе). Вы можете даже переполнить буфер строки формата.

4 голосов
/ 03 мая 2011

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

3 голосов
/ 03 мая 2011

Обратите внимание, что до тех пор, пока ваши буферы не меньше, чем strlen(input_string)+1, спецификаторы %s или %[ не могут переполниться.Вы также можете использовать ширину поля в спецификаторах, если хотите применить более строгие ограничения, или вы можете использовать %*s и %*[ для подавления присваивания и вместо этого использовать %n до и после, чтобы получить смещения в исходной строке, изатем используйте их, чтобы прочитать результирующую подстроку на месте из входной строки.

3 голосов
/ 03 мая 2011

Да, это так ... если вы указали ширину строки, чтобы избежать проблем, связанных с переполнением буфера.

В любом случае, как показал нам @Mehrdad, будут возможные проблемы, если размер буфера не будет установлен во время компиляции. Я полагаю, что ограничение длины строки, которая может быть передана в sscanf, может устранить проблему.

2 голосов
/ 18 мая 2018

Все функции scanf имеют фундаментальные недостатки проектирования, только некоторые из которых могут быть исправлены.Они не должны использоваться в производственном коде.

  • Числовое преобразование имеет полное неопределенное поведение типа "демон летает из носа", если значение выходит за пределы представимого диапазона переменнойВы сохраняете значение в. Я не придумываю это .Библиотеке C разрешено сбой вашей программы только потому, что кто-то набрал слишком много вводимых цифр.Даже если он не падает, он не обязан делать что-то разумное.Обходного пути нет.

  • Как указывалось в нескольких других ответах, %s столь же опасен, как и печально известный gets. возможно избежать этого, используя либо модификатор 'm', либо ширину поля, но вы должны помнить об этом для каждого отдельного текстового поля, которое вы хотите преобразовать, и вам нужно связать полеширины в строке формата - вы не можете передать sizeof(buff) в качестве аргумента.

  • Если входные данные не совсем соответствуют строке формата, sscanf не говорит вамсколько символов во входной буфер он получил до того, как сдался.Это означает, что единственная практическая политика устранения ошибок - это сброс всего входного буфера.Это может быть в порядке, если вы обрабатываете файл, который представляет собой простой линейный массив записей какого-либо типа (например, с файлом CSV, «пропустить искаженную строку и перейти к следующей» - существенная ошибкаполитика восстановления), но если входные данные имеют больше структуры, чем это, вы попадаете.

В C анализируйте задания, которые недостаточно сложны, чтобы оправдать использование lex иyacc обычно лучше всего делать либо с регулярным выражением POSIX (regex.h), либо с ручным анализом строк.strto* функции преобразования чисел do имеют четко определенное и полезное поведение при переполнении, а do сообщают вам, как символы ввода они использовали, а string.h имеет множество удобных функцийдля свернутых вручную парсеров (strchr, strcspn, strsep и т. д.).

2 голосов
/ 02 апреля 2013

Есть 2 пункта, чтобы позаботиться.

Выходной буфер [с].

Как уже упоминали другие, если вы указали размер, меньший или равный размеру выходного буфера, в строке формата, которую вы в безопасности.

Входной буфер.

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

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

...