Используете ли вы функции TR 24731 "безопасные"?

Комитет ISO C (ISO/IEC JTC1/SC21/WG14) опубликовал TR 24731-1 и работает над TR 24731-2:

TR 24731-1: Расширения библиотеки C Часть I: Интерфейсы проверки границ

WG14 работает над TR по более безопасным функциям библиотеки C. Этот TR ориентирован на модификацию существующих программ, часто добавляя дополнительный параметр с длиной буфера. Последний проект представлен в документе N1225. Обоснование содержится в документе N1173. Это должно стать Техническим отчетом типа 2.

TR 24731-2: Расширения библиотеки C - Часть II: Динамические функции распределения

WG14 работает над TR по более безопасным функциям библиотеки C. Этот TR ориентирован на новые программы, используя динамическое распределение вместо дополнительного параметра для длины буфера. Последний проект представлен в документе N1337. Это должно стать Техническим отчетом типа 2.

Вопросы

  • Используете ли вы библиотеку или компилятор с поддержкой функций TR24731-1?
  • Если да, то какой компилятор или библиотека и на какой платформе (-ах)?
  • Вы обнаружили какие-либо ошибки в результате исправления кода для использования этих функций?
  • Какие функции предоставляют наибольшую ценность?
  • Есть ли какие-либо значения, которые не дают значения или отрицательного значения?
  • Планируете ли вы использовать библиотеку в будущем?
  • Вы вообще отслеживаете работу TR24731-2?

Ответ 1

Я был вокальным критиком этих ТР с момента их создания (когда это был единственный ТР) и никогда не использовал бы их ни в одном из моих программ. Они маскируют симптомы вместо того, чтобы рассматривать причины, и я считаю, что если что-то они окажут негативное влияние на дизайн программного обеспечения, поскольку они обеспечивают ложное чувство безопасности, а не продвигают существующие методы, которые могут достичь одних и тех же целей намного эффективнее. Я не одинок, на самом деле я не знаю ни одного крупного сторонника за пределами комитета, разрабатывающего эти ТР.

Я использую glibc и как таковой знаю, что мне пощадят, имея дело с этой глупостью, поскольку Ульрих Дреппер, ведущий сопровождающий для glibc, сказал о теме:

Предлагаемая безопасная (r) библиотека ISO C не удается полностью решить проблему.... Предлагая сделать жизнь программист еще сложнее не собирается Помогите. Но это именно то, что предложенный.... Они все требуют больше работа должна быть выполнена или просто глупо.

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

Остинская группа (ответственная за поддержание POSIX) представила очень критический обзор TR, их комментарии и отзывы в комитете здесь. Обзор Austin Group очень хорошо описывает многие проблемы с TR, поэтому я не буду вдаваться в подробности здесь.

Итак, нижняя строка: я не использую реализацию, которая поддерживает или будет поддерживать это, я не планирую использовать эти функции, и я не вижу положительного значения в TR. Я лично считаю, что единственная причина, по которой TR все еще жив в любой форме, состоит в том, что Microsoft сильно забивает Microsoft, которая в последнее время оказалась очень способной к тому, чтобы все протаращилось, хотя комитеты по стандартам, несмотря на широко распространенную оппозицию. Если эти функции когда-либо стандартизированы, я не думаю, что они когда-либо станут широко использоваться, поскольку это предложение существует уже несколько лет и не получило никакой реальной поддержки сообщества.

Ответ 2

Прямой ответ на вопрос

Мне нравится ответ Роберта, но у меня также есть некоторые взгляды на вопросы, которые я поднял.

  • Используете ли вы библиотеку или компилятор с поддержкой функций TR24731-1?

    Нет не знаю

  • Если да, то какой компилятор или библиотека и на какой платформе?

    Я полагаю, что функции предоставляются MS Visual Studio (например, MS VC++ 2008 Edition), и есть предупреждения, побуждающие вас использовать их.

  • Вы обнаружили какие-либо ошибки в результате исправления вашего кода для использования этих функций?

    Еще нет. И я не ожидаю раскрыть многие в моем коде. Некоторый другой код, с которым я работаю - возможно. Но я еще не убежден.

  • Какие функции обеспечивают наибольшую ценность?

    Мне нравится тот факт, что семейство функций printf_s() не принимает спецификатор формата ' %n '.

  • Есть ли какие-либо, которые не дают значения или отрицательного значения?

    Функции tmpfile_s() и tmpnam_s() - ужасное разочарование. Им действительно нужно было работать как mkstemp() который одновременно создает файл и открывает его, чтобы гарантировать отсутствие уязвимости TOCTOU (время проверки, время использования). В настоящее время эти два обеспечивают очень мало значения.

    Я также думаю, что strerrorlen_s() обеспечивает очень небольшое значение.

  • Планируете ли вы использовать библиотеку в будущем?

    Я нахожусь в двух умах об этом. Я начал работать над библиотекой, которая будет реализовывать возможности TR 24731 по сравнению со стандартной библиотекой C, но был пойман количеством модульного тестирования, необходимого, чтобы продемонстрировать, что он работает правильно. Я не уверен, стоит ли продолжать это. У меня есть некоторый код, который я хочу портировать на Windows (в основном из-за извращенного желания обеспечить поддержку на всех платформах - он работает над производными Unix уже пару десятилетий). К сожалению, чтобы заставить его компилироваться без предупреждений от компиляторов MSVC, я должен оштукатурить код, чтобы не допустить засорения MSVC, используя совершенно надежные (при тщательном использовании) стандартные функции библиотеки C. И это не аппетитно. Достаточно плохо, что мне приходится иметь дело с системой, которая развивалась в течение этого периода в течение большей части двух десятилетий; необходимость иметь дело с кем-то, идея веселья (заставляющая людей принимать ТР 24731, когда им это не нужно) раздражает. Это было частично, почему я начал разработку библиотеки - чтобы позволить мне использовать те же интерфейсы в Unix и Windows. Но я не уверен, что я буду делать отсюда.

  • Вы отслеживаете работу TR24731-2 вообще?

    Я не отслеживал его, пока не пошел на сайт стандартов во время сбора данных для вопроса. Функции asprintf() и vasprintf(), вероятно, полезны; Я бы использовал их. Я не уверен насчет функций ввода-вывода потока памяти. strdup() на уровне C была бы огромным шагом вперед. Это кажется мне менее спорным, чем часть 1 (проверка границ) интерфейсов.

В целом, я не убежден в части 1 "Интерфейсы проверки границ". Материал в проекте части 2 "Динамические функции распределения" лучше.

Если бы это зависело от меня, я бы немного продвинулся по линии части 1, но я бы также пересмотрел интерфейсы в стандартной C-библиотеке C99, которые возвращают char * в начало строки (например, strcpy() и strcat()), чтобы вместо возврата указателя на начало они возвращали указатель на нулевой байт в конце новой строки. Это сделало бы некоторые общие идиомы (такие как многократные конкатенации строк в конце другой) более эффективными, потому что это сделало бы тривиальным, чтобы избежать квадратичного поведения, демонстрируемого кодом, который многократно использует strcat(). Все замены обеспечат нулевое завершение выходных строк, как это делают версии TR24731. Я не совсем против идеи проверки интерфейса и функций обработки исключений. Это сложный бизнес.


Реализация Microsoft отличается от стандартной спецификации

Обновление (2011-05-08)

Смотрите также этот вопрос. К сожалению, и, что крайне важно для полезности функций TR24731, определения некоторых функций различаются между реализацией Microsoft и стандартом, что делает их бесполезными (для меня). Мой ответ там цитирует vsnprintf_s().

Например, TR 24731-1 говорит, что интерфейс для vsnprintf_s():

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdarg.h>
#include <stdio.h>
int vsnprintf_s(char * restrict s, rsize_t n,
                const char * restrict format, va_list arg);

К сожалению, MSDN говорит, что интерфейс для vsnprintf_s():

int vsnprintf_s(
   char *buffer,
   size_t sizeOfBuffer,
   size_t count,
   const char *format,
   va_list argptr 
);

параметры

  • буфер - место хранения для вывода.
  • sizeOfBuffer - Размер буфера для вывода.
  • count - Максимальное количество символов для записи (не включая завершающий ноль) или _TRUNCATE.
  • формат - спецификация формата.
  • argptr - указатель на список аргументов.

Обратите внимание, что это не просто вопрос отображения типов: число фиксированных аргументов отличается и поэтому несовместимо. Мне также неясно (и, по-видимому, также и комитету по стандартам), какая польза от наличия обоих 'sizeOfBuffer' и 'count'; она выглядит как одна и та же информация дважды (или, по крайней мере, код обычно пишется с одинаковым значением для обоих параметров).

Точно так же существуют проблемы с scanf_s() и его родственниками. Microsoft говорит, что тип параметра длины буфера является unsigned (явно указав "параметр размера имеет тип unsigned, а не size_t "). Напротив, в Приложении K параметр размера имеет тип rsize_t, который является ограниченным вариантом size_t (rsize_t является другим именем для size_t, но RSIZE_MAX меньше, чем SIZE_MAX). Итак, опять же, код, вызывающий scanf_s(), должен быть написан по-разному для Microsoft C и Standard C.

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


Изменения в Microsoft vsnprintf() в Visual Studio 2015

В документации по Visual Studio 2015 для vsnprintf() отмечается, что интерфейс изменился:

Начиная с UCRT в Visual Studio 2015 и Windows 10, vsnprintf больше не идентичен _vsnprintf. Функция vsnprintf соответствует стандарту C99; _vnsprintf сохраняется для обратной совместимости.

Однако интерфейс Microsoft для vsnprintf_s() не изменился.


Другие примеры различий между Microsoft и Приложением K

Стандартный вариант С11 localtime_s() определен в Приложении K.3.8.2.4 ИСО/МЭК 9899: 2011 как:

struct tm *localtime_s(const time_t * restrict timer,
                       struct tm * restrict result);

по сравнению с MSDN вариант localtime_s() определенный как:

errno_t localtime_s(struct tm* _tm, const time_t *time);

и вариант POSIX localtime_r() определенный как:

struct tm *localtime_r(const time_t *restrict timer,
                       struct tm *restrict result);

Стандарт C11 и функции POSIX эквивалентны, кроме имени. Интерфейс Microsoft отличается по интерфейсу, хотя и имеет общее имя со стандартом C11.

Другим примером различий является Microsoft strtok_s() и Приложение K strtok_s():

char *strtok_s(char *strToken, const char *strDelimit, char **context); 

против:

char *strtok_s(char * restrict s1, rsize_t * restrict s1max, const char * restrict s2, char ** restrict ptr);

Обратите внимание, что вариант Microsoft имеет 3 аргумента, тогда как вариант приложения K имеет 4. Это означает, что список аргументов для Microsoft strtok_s() совместим с POSIX strtok_r() - поэтому их вызовы эффективно взаимозаменяемы, если вы измените имя функции (например, макросом) - но версия Standard C (Приложение K) отличается от версии с дополнительным аргументом.

Вопрос Различные объявления qsort_r() в Mac и Linux имеют ответ, который также обсуждает qsort_s() как определено Microsoft, и qsort_s() как определено TR24731-1 - опять же, интерфейсы разные.


ISO/IEC 9899: 2011 - Стандарт C11

Стандарт C11 (проект на декабрь 2010 года; вы можете в одно время получить PDF-копию окончательного стандарта ISO/IEC 9899: 2011 из интернет-магазина ANSI за 30 долларов США), в котором есть функции TR24731-1 в качестве дополнительного оборудования. часть стандарта. Они определены в Приложении K (Интерфейсы проверки границ), которое является "нормативным", а не "информационным", но является необязательным.

Стандарт C11 не имеет функций TR24731-2 - это печально, потому что функция vasprintf() и ее родственники могут быть действительно полезными.

Краткое резюме:

  • C11 содержит TR24731-1
  • C11 не содержит TR24731-2
  • C18 такой же, как C11 по TR24731.

Предложение удалить приложение K от преемника C11

Дедупликатор указал в комментарии на другой вопрос, что есть предложение перед комитетом по стандарту ISO C (ISO/IEC JTC1/SC22/WG14)

Он содержит ссылки на некоторые из существующих реализаций функций Приложения K - ни одна из них широко не используется (но вы можете найти их в документе, если вам интересно).

Документ заканчивается рекомендацией:

Поэтому мы предлагаем, чтобы Приложение K было либо исключено из следующего пересмотра стандарта C, либо устарело, а затем удалено.

Я поддерживаю эту рекомендацию.

Стандарт C18 не изменил статус Приложения K. Существует документ N2336, в котором предлагается внести некоторые изменения в Приложение K, исправляя его дефекты, а не устраняя их полностью.

Ответ 3

Хорошо, теперь стенд для TR24731-2:

Да, я использовал asprintf()/vasprintf() с тех пор, как видел их в glibc, и да, я их очень сторонник.

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

Я также очень поддерживаю функции memstream: подобно asprintf(), open_memstream() (не fmemopen() !!!) выделяет достаточно большой буфер для вас и дает вам FILE* для печати, поэтому Ваши функции печати могут совершенно не знать, печатаются ли они в строку или файл, и вы можете просто забыть, сколько места вам понадобится.

Ответ 4

Используете ли вы библиотеку или компилятор с поддержкой функций TR24731-1? Если да, то какой компилятор или библиотека и на какой платформе (-ах)?

Да, Visual Studio 2005 и 2008 (очевидно, для разработки Win32).

Вы обнаружили какие-либо ошибки в результате исправления кода для использования этих функций?

Сортировка.... Я написал свою собственную библиотеку безопасных функций (всего около 15, которые мы часто используем), которые будут использоваться на нескольких платформах - Linux, Windows, VxWorks, INtime, RTX и uItron. Причиной создания безопасных функций были:

  • Мы столкнулись с большим количеством ошибок из-за неправильного использования стандартных функций C.
  • Я не был доволен информацией, переданной или возвращенной из функций TR или в некоторых случаях их альтернатив POSIX.

Как только функции были написаны, было обнаружено больше ошибок. Так что да, было значение в использовании функций.

Какие функции предоставляют наибольшую ценность?

Более безопасные версии vsnprintf, strncpy, strncat.

Есть ли какие-либо значения, которые не дают значения или отрицательного значения?

fopen_s и подобные функции добавляют мне очень мало значения для меня лично. Я в порядке, если fopen возвращает NULL. Вы всегда должны проверить возвращаемое значение функции. Если кто-то игнорирует возвращаемое значение fopen, что собирается заставить их проверить возвращаемое значение fopen_s? Я понимаю, что fopen_s вернет более конкретную информацию об ошибках, которая может быть полезна в некоторых контекстах. Но для того, над чем я работаю, это не имеет значения.

Планируете ли вы использовать библиотеку в будущем?

Мы используем его сейчас - в нашей собственной "безопасной" библиотеке.

Вы вообще отслеживаете работу TR24731-2?

Нет.

Ответ 5

Нет, эти функции абсолютно бесполезны и не служат никакой цели, кроме как поощрять создание кода, поэтому он компилируется только в Windows.

snprintf абсолютно безопасен (когда он выполняется правильно), поэтому snprintf_s бессмысленно. strcat_s уничтожит данные, если буфер переполнен (очищая конкатенированную строку). Существует много других примеров полного незнания того, как все работает.

Реальными полезными функциями являются BSD strlcpy и strlcat. Но и Microsoft, и Drepper отвергли их по своим эгоистичным причинам, до раздражения программистов C во всем мире.