Вы используете «безопасные» функции TR 24731? - PullRequest
71 голосов
/ 17 декабря 2008

Комитет 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 ]

64 голосов
/ 17 декабря 2008

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

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

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

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

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

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

28 голосов
/ 17 декабря 2008

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

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

  • Используете ли вы библиотеку или компилятор с поддержкой функций 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

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

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. Это означает, что список аргументов для strtok_s() корпорации Майкрософт совместим с strtok_r() POSIX - так что их вызовы эффективно взаимозаменяемы, если вы изменяете имя функции (например, макросом), но версия 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 USD) имеет функции TR24731-1 в качестве дополнительной части стандарта. Они определены в Приложении K (Интерфейсы проверки границ), которое является «нормативным», а не «информационным», но является необязательным.

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

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

  • C11 содержит TR24731-1
  • C11 не содержит TR24731-2
  • C18 - это то же самое, что и C11 w.r.t TR24731.

Предложение об исключении Приложения K из преемника C11

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

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

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

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

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

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

7 голосов
/ 28 июня 2013

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

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

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

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

5 голосов
/ 11 февраля 2014

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

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

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

5 голосов
/ 15 мая 2009

Используете ли вы библиотеку или компилятор с поддержкой функций 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?

номер

...