Чи використовуєте ви функції TR 24731 "безпечно"? [зачинено]


76

Комітет 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
@MarcusJ: Хммм - мені потрібно було б пояснити, що ви маєте на увазі під словом "додати strlen()до коду". Безумовно, бувають випадки, коли strlen()не правильна відповідь, наприклад, при передачі буфера функції вводу-виводу (наприклад gets_s()). Але, можливо, ви можете детальніше розказати про те, про що думаєте?
Джонатан Леффлер

1
@MarcusJ: Ви не можете використовувати, realloc()оскільки функції, які потребують захисту, не розподіляються. Наприклад, strcpy()функція не робить розподілу пам'яті; ви не можете розумно змінити його для виділення пам'яті, навіть якщо у вас є збір сміття, оскільки люди зазвичай не використовують повернене значення, а використовують значення, передане як перший аргумент для strcpy()подальших операцій. Подібні проблеми виникають із gets()і strcat(). Ті, принаймні, повертають a, char *що може вказувати на перерозподілений простір (не те, що є гарантія, що аргументи були розподілені). [… Продовження…]
Джонатан Леффлер

1
[… Продовження…] Проблема гірша з такими функціями, sprintf()які не повертають a char *; вони ніяк не можуть повідомити телефонний код, що вони „перерозподілили” пам’ять, куди був поміщений результат. Зверніть увагу, що однією з причин, чому TR 24731-2 не потрапив у C11, було те, що вони будуть першими функціями, які явно виконують розподіл пам'яті - крім malloc()інших. Будь ласка, знайдіть час, щоб вивчити, що роблять функції, що роблять функції Додатку K / TR 24731-1, обгрунтування того, чому вони це роблять тощо. Є кілька вагомих причин прийнятих рішень.
Джонатан Леффлер

1
Хм, це питання насправді не відповідає Stack Overflow в наш час;)
Antti Haapala

1
@AnttiHaapala: можливо, ні (хоча я думаю, що ТО стає надто суворим в наші дні). Я хотів би аргументувати хоча б історичний статус для нього (історичний замок). Її можна переформулювати у відповідності до "Чи можна використовувати функції TR24731 (Додаток К)?", Але…. Зокрема, я вважаю, що інформація у моїй відповіді корисна програмістам на С, і її слід розміщувати десь у розділі С SO. Колись це могло бути включено у „документи” - цього зараз не станеться.
Джонатан Леффлер

Відповіді:


67

Я був критичним критиком цих ТР з моменту їх створення (коли це був один ТР) і ніколи не використовував би їх у жодному зі своїх програм. Вони маскують симптоми, а не звертаються до причин, і, на мою думку, вони в будь-якому випадку матимуть негативний вплив на розробку програмного забезпечення, оскільки вони дають помилкове відчуття безпеки, а не сприяють існуючим практикам, які можуть досягти тих самих цілей набагато ефективніше. Я не одна, насправді мені не відомий жоден великий прихильник поза комітетом, який розробляє ці ТР.

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

Запропонована безпечна (r) бібліотека ISO C не може повністю вирішити проблему. ... Запропонувати ускладнити життя програміста не допоможе. Але саме це пропонується. ... Усі вони вимагають більше роботи, або просто дурні.

Далі він детально описує проблеми з низкою запропонованих функцій і в іншому місці зазначив, що glibc ніколи не підтримає цього.

Austin Group (відповідальна за підтримку POSIX) надала дуже критичний огляд TR, їх коментарі та відповіді комітетів, доступні тут . Огляд Austin Group робить дуже гарну роботу з деталізацією багатьох проблем з ТР, тому я не буду вдаватися до окремих деталей тут.

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


22
Посилання на думку Ульріха Дреппера як на будь-яку владу - це хороший спосіб зняти свій аргумент на місці, незалежно від будь-яких інших обставин викупу.
Павло Мінаєв

56
@Pavel, я назвав Drepper як авторитет для glibc . Незважаючи на будь-які особисті проблеми, які у вас можуть виникати з ним, він є провідним супроводжувачем glibc і в значній мірі вирішує, що буде, а що не буде включено в glibc, подобається це вам чи ні. Я взагалі не використовував свою справу проти ТР на його думку, ваш коментар, схоже, ґрунтується на сильній особистій неприязні до однієї особи, і якщо це засліплює вас від можливості побачити загальну картину, це помилка, вам слід попрацювати на.
Роберт Гембл

7
+1. Люди, які не знають, що роблять, повинні використовувати VB, а не C :-)
paxdiablo

8
Для перемоги: кілька буферів libupnp переповнюється . Більш безпечні функції, які вам не подобаються, зупинили б більшість із них. Хороша робота з розповсюдження поганих порад :)
jww

10
^^^ Використання програмістів, які знають, як правильно програмувати, зупинило б усіх ...
Джон Хасколл

30

Пряма відповідь на питання

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

  • Чи використовуєте ви бібліотеку або компілятор з підтримкою функцій TR24731-1?

    Ні, ні.

  • Якщо так, то який компілятор чи бібліотека та на якій платформі?

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

  • Ви виявили помилки в результаті виправлення коду для використання цих функцій?

    Ще ні. І я не сподіваюся розкрити багато в моєму коді. Деякий інший код, з яким я працюю - можливо. Але я ще не переконаний.

  • Які функції надають найбільше значення?

    Мені подобається той факт, що сімейство функцій printf_s () не приймає %nспецифікатор формату ' '.

  • Чи є такі, що не надають значення або від’ємного значення?

    Функції tmpfile_s()and tmpnam_s()викликають жахливе розчарування. Їм справді потрібно було працювати більше якmkstemp() який як створює файл, так і відкриває його, щоб переконатися у відсутності вразливості TOCTOU (час перевірки, час використання). По суті, ці два дають дуже мало цінності.

    Я також думаю, що це strerrorlen_s()забезпечує дуже мало цінності.

  • Чи плануєте Ви використовувати бібліотеку в майбутньому?

    Я в двох думках про це. Я розпочав роботу над бібліотекою, яка реалізовувала б можливості TR 24731 у порівнянні зі стандартною бібліотекою C, але мене вловлював обсяг модульного тестування, необхідний, щоб продемонструвати, що вона працює правильно. Я не впевнений, чи продовжувати це. У мене є якийсь код, який я хочу перенести на Windows (головним чином, через збочене бажання надати підтримку на всіх платформах - це працює над похідними Unix вже пару десятиліть). На жаль, щоб змусити його компілюватись без попереджень компіляторів MSVC, мені доводиться обмазувати код речами, щоб уникнути, щоб MSVC не засмучував мене, використовуючи цілком надійні (при обережному використанні) стандартні функції бібліотеки C. І це не апетитно. Досить погано, що мені доводиться мати справу з більшістю системи, яка склалася за цей період на два десятки років; доводиться мати справу з чиєюсь ідеєю розваги (змусити людей прийняти TR 24731, коли їм це не потрібно) дратує. Саме тому я почав розробку бібліотеки - щоб дозволити мені використовувати однакові інтерфейси на Unix та Windows. Але я не впевнений, що звідси буду робити.

  • Ви взагалі відстежуєте роботу TR24731-2?

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

Загалом, я не впевнений у частині 1 «Інтерфейси перевірки обмежень». Матеріал у проекті частини 2 "Функції динамічного розподілу" є кращим.

Якби це залежало від мене, я б рухався дещо по лініях частини 1, але я також переглянув інтерфейси в стандартній бібліотеці C99 C, які повертають a char *до початку рядка (наприклад, strcpy()і strcat()), щоб замість повертаючи вказівник на початок, вони повертали вказівник на нульовий байт в кінці нового рядка. Це зробило б деякі загальні ідіоми (наприклад, неодноразове об'єднання рядків у кінець іншої) більш ефективними, оскільки це зробило б тривіальним уникнення квадратичної поведінки коду, який неодноразово використовується strcat(). Усі заміни забезпечать припинення вихідних рядків, як у версіях TR24731. Я не зовсім не люблю ні ідею перевірки інтерфейсу, ні функції обробки винятків. Це складна справа.


Реалізація корпорації Майкрософт відрізняється від стандартної специфікації

Оновлення (08.05.2011)

Дивіться також це питання . На жаль і фатально для корисності функцій TR24731, визначення деяких функцій відрізняється між реалізацією Microsoft та стандартом, що робить їх марними (для мене). Моя відповідь там наводиться vsnprintf_s().

Наприклад, TR 24731-1 каже, що інтерфейс vsnprintf_s():

На жаль, MSDN каже, що інтерфейс vsnprintf_s():

Параметри

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

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

Подібним чином є також проблеми з scanf_s()та його родичами. Корпорація Майкрософт каже, що тип параметра довжини буфера є unsigned(явно вказуючи "Параметр розміру має тип unsigned, а не size_t"). На відміну від цього, у Додатку К параметр розміру має тип 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()визначений у ISO / IEC 9899: 2011 Додаток K.3.8.2.4 як:

порівняно з варіантом MSDN, localtime_s()визначеним як:

і варіант POSIX, localtime_r()визначений як:

Функції стандарту C11 і POSIX еквівалентні, крім імені. Функція Microsoft відрізняється в інтерфейсі, хоча вона має спільне ім'я зі стандартом C11.

Інший приклад відмінностей Microsoft s » strtok_s()і додаток К - х strtok_s():

проти:

Зверніть увагу, що варіант Microsoft має 3 аргументи, тоді як варіант Додатку К - 4. Це означає, що список аргументів для Microsoft strtok_s()сумісний з POSIXstrtok_r() - тому виклики до них ефективно взаємозамінні, якщо ви зміните назву функції (наприклад, за допомогою макросу) - але версія стандарту С (Додаток К) відрізняється від обох додатковим аргументом.

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


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

Стандарт C11 ( проект грудня 2010 року ; ви могли свого часу отримати копію остаточного стандарту ISO / IEC 9899: 2011 у веб-магазині ANSI за 30 доларів США), як додаткові функції TR24731-1 частина стандарту. Вони визначені в Додатку К (Інтерфейси перевірки обмежень), який є "нормативним", а не "інформаційним", але є необов'язковим.

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

Короткий підсумок:

  • C11 містить TR24731-1
  • C11 не містить TR24731-2
  • C18 те саме, що C11 wrt TR24731.

Пропозиція вилучити Додаток К із наступника С11

Дедулікатор в коментарі до іншого питання зазначив, що є пропозиція перед комітетом зі стандартів ISO C (ISO / IEC JTC1 / SC22 / WG14)

Він містить посилання на деякі з існуючих реалізацій функцій Додатку К - жодна з них не використовується широко (але ви можете знайти їх у документі, якщо вам цікаво).

Документ закінчується рекомендацією:

Тому ми пропонуємо, щоб Додаток К або був вилучений із наступного перегляду стандарту С, або припинений, а потім видалений.

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

Стандарт С18 не змінив статусу Додатку К. Існує стаття N2336, яка виступає за внесення деяких змін до Додатку К, виправлення його дефектів, а не його взагалі видалення.


3
Що ж, якщо РС суперечить стандарту, потрібно буде змінити РС, а не стандарт ...
cmaster - відновити Моніка

5
Я теж хотів би так думати, але вони мають встановлену базу і не порушують зворотну сумісність, тому на практиці це продовжує означати, що MS не підтримуватиме стандарт C, більш сучасний, ніж C89 (C90) - на жаль.
Джонатан Леффлер

Ви можете спробувати використати компілятор clang у вікнах clang.llvm.org/get_started.html . Він підтримує C17 і працює досить легко з інструментами візуальної студії.
annoying_squid

7

Гаразд, тепер стенд для TR24731-2:

Так, я використовував asprintf()/ з vasprintf()тих пір, як бачив їх у glibc, і так, я дуже їх прихильник.

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

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


Дякуємо за відгук. TR24731-2, на жаль, не є частиною стандарту C2011, але, як правило, є корисним набором функцій. У мене також є застереження щодо fmemopen()функції в POSIX. open_memstream()Функція цікава. У його використанні, я підозрюю, є деякі помилки, оскільки ви передаєте вказівники на покажчик буфера та змінну розміру. Але в цілому TR23731-2 - це добре.
Джонатан Леффлер

Я хотів би бачити, ніж vasprintf"загальну" функцію vformat, яка приймає на додачу до звичайних аргументів vprintf символи int(*func)(void*,size_t,char const*)a та a void*, а також викликає надану функцію для кожного "діапазону" символів, що виводиться [повернення достроково, якщо функція повертається ненульове значення]. Можна було б синтезувати автоматичний розподіл спринту з такої функції, але загальна версія також буде сумісна з користувацькими розподільниками.
supercat

@supercat У цих рядках було кілька stdioваріантів, які дозволяють вказати власні функції читання / запису. Так, наприклад, ви можете щось зробити FILE *fp = ffunopen(myreadfunc, mywritefunc), а потім зателефонувати fprintfабо будь- яку функцію stdio і викликати зворотний виклик (и). Я також бачив принаймні одну реалізацію fmemopenваріанту, в який було вбудоване автоматичне розподіл - знову ж це означає, що ви можете отримати автоматичне розподіл для будь-якої послідовності вихідних викликів, а не тільки *printf.
Стів Саміт

@SteveSummit: Надання FILE*вказівника на таблицю функцій було б дуже корисним, але головним моїм судженням було те, що підпрограми бібліотеки не повинні покладатися, mallocа натомість дозволяти користувацькому коду керувати пам'яттю будь-якими способами, які найбільш підходять для передбачуваного випадку використання .
supercat

5

Чи використовуєте ви бібліотеку або компілятор з підтримкою функцій 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 скрізь.


2
Дякуємо за вступ. Я не впевнений, що "повне невігластво" доречно, але я згоден з тим, що нові функції не завжди є таким значним покращенням, як це могло б бути.
Джонатан Леффлер

Я вважаю, що функція у стилі strlcat могла б ефективніше прийняти покажчик на кінець буфера призначення і повернути покажчик на кінцевий нульовий байт призначення. Це дозволило б повернути значення одного виклику іншому, щоб об’єднати декілька значень у рядок без необхідності повторного сканування цільового рядка кожного разу.
supercat
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.