Вы используете "безопасные" функции 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 вообще?

5 ответов

Решение

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

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

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

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

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

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

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

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

  • Используете ли вы библиотеку или компилятор с поддержкой функций 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. И это не аппетитно. Достаточно плохо, что мне приходится иметь дело с системой, которая развивалась в течение этого периода на протяжении большей части двух десятилетий; раздражает необходимость иметь дело с чьей-то идеей веселья (заставляющей людей принимать TR 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() и Приложение К 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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Нет.

Другие вопросы по тегам