Подтвердить что ты не робот

Почему strtok() считается небезопасным?

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

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

4b9b3361

Ответ 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" проанализирует "мир привет". Обратите внимание, что он разбивается на/и игнорирует тот факт, что он находится в круглой скобке.