Почему strtok () считается небезопасным? - PullRequest
27 голосов
/ 14 мая 2011

Какие функции strtok небезопасны (с точки зрения переполнения буфера), на которые мне нужно обратить внимание?

Что немного странно для меня, так это то, что strtok_s (который является "безопасным") в Visual C ++ имеет дополнительный параметр "context", но похоже, что он такой же в других отношениях ... это то же самое, или это на самом деле другое?

Ответы [ 4 ]

24 голосов
/ 14 мая 2011

В соответствии с разделом strtok_s этого документа :

6.7.3.1 Функция strtok_s Функция strtok_s исправляет две проблемы в функции strtok:

  1. Новый параметр, s1max, предотвращает сохранение strtok_s вне токенизируемой строки.(Строка, разделенная на токены, является как входом, так и выходом функции, поскольку strtok_s сохраняет в строке нулевые символы.)
  2. Новый параметр ptr устраняет статическое внутреннее состояние, которое предотвращает восстановление strtok.абитуриент (подпункт 1.1.12).(Функция wcstok ИСО / МЭК 9899 и функция strtok_r ИСО / МЭК 9945 (POSIX) решают эту проблему одинаково.)
12 голосов
/ 14 мая 2011

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

BUGS

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

  • Эти функции изменяют свой первый аргумент.
  • Эти функции нельзя использовать для константных строк.
  • Идентификаторсимвол-разделитель потерян.
  • Функция strtok() использует статический буфер при разборе, поэтому он не является потокобезопасным.Используйте strtok_r(), если это важно для вас.
5 голосов
/ 14 мая 2011

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

Однако даже в VC ++, где strtok является потокобезопасным, это все еще немного странно - вы не можете использовать strtok () для разных строк в одном потоке в одно и то же время. Например, это не сработает:

     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 является поточно-ориентированным с VC ++, он не является реентерабельным.

Что обеспечивает strtok_s (или strtok_r везде) - явное состояние, и с этим strtok становится реентерабельным.

0 голосов
/ 14 мая 2011

Если у вас нет правильно завершенной нулевой строки; Вы окажетесь в переполнении буфера. Также обратите внимание (это то, чему я научился нелегко), strtok, похоже, не заботится о внутренних строках. И.Е. наличие "привет" / "мир" будет анализировать "привет" / "мир", тогда как "привет / мир" будет анализировать в "привет мир". Обратите внимание, что он разделяется на / и игнорирует тот факт, что он находится в скобках.

...