Почему strtok() считается небезопасным?
Какая функция strtok
является небезопасной (с точки зрения переполнения буфера), которую я должен отслеживать?
Для меня немного странно, что strtok_s
(который является "безопасным" ) в Visual С++ имеет дополнительный "контекстный" параметр, но он похож на него одинаковым по-другому... это то же самое, или это действительно другое?
Ответы
Ответ 1
В соответствии с разделом strtok_s этот документ:
6.7.3.1 Функция strtok_s Функция strtok_s устраняет две проблемы в функции strtok:
- Новый параметр s1max предотвращает хранение strtok_s за пределами строка является токенизируемой. (Струна разделение на токены - это как ввод и вывод функции с strtok_s хранит нулевые символы в строка.)
- Новый параметр, ptr, устраняет статическое внутреннее состояние, которое предотвращает повторный вход strtok (Подпункт 1.1.12). (ИСО/МЭК 9899 функции wcstok и ISO/IEC 9945 (POSIX) функция strtok_r исправить это проблема идентична.)
Ответ 2
В этом нет ничего опасного. Вам просто нужно понять, как это работает и как его использовать. После того, как вы напишете свой код и unit test, для повторного запуска unit test с valgrind потребуется всего несколько минут, чтобы убедиться, что вы работаете с границами памяти. На странице руководства написано все:
ОШИБКИ
Будьте осторожны при использовании этих функций. Если вы их используете, обратите внимание, что:
- Эти функции изменяют свой первый аргумент.
- Эти функции не могут использоваться для постоянных строк.
- Личность разделительного символа теряется.
- Функция
strtok()
использует статический буфер при разборе, поэтому он не является потокобезопасным. Используйте strtok_r()
, если это имеет значение для вас.
Ответ 3
strtok безопасен в Visual С++ (но нигде больше), поскольку он использует локальное хранилище потоков для сохранения своего состояния между вызовами. Во всем мире глобальная переменная используется для сохранения состояния strtok().
Однако даже в VС++, где strtok является потокобезопасным, он все еще немного странный - вы не можете использовать strtok() s в разных строках в одном и том же потоке одновременно. Например, это не сработает:
token = strtok( string, seps );
while(token)
{
printf("token=%s\n", token)
token2 = strtok(string2, seps);
while(token2)
{
printf("token2=%s", token2);
token2 = strtok( NULL, seps );
}
token = strtok( NULL, seps );
}
Причина, по которой это не сработает - для каждого потока только одно состояние может быть сохранено в локальном хранилище потоков, и здесь нужно было бы 2 состояния - для первой строки и для второй строки. Поэтому, хотя strtok является потокобезопасным с VС++, он не реентерабелен.
Что strtok_s (или strtok_r везде) предоставляет - явное состояние, и с этим strtok становится реентерабельным.
Ответ 4
Если у вас нет нулевой строки с нулевым завершением; вы попадете в переполнение буфера. Также обратите внимание (это то, чему я научился с трудом) strtok, похоже, не заботится о внутренних строках. И.Е. "hello" / "world" проанализирует "привет" / "мир", тогда как "hello/world" проанализирует "мир привет". Обратите внимание, что он разбивается на/и игнорирует тот факт, что он находится в круглой скобке.