82

ISO C 委員会 ( ISO/IEC JTC1/SC21/WG14 ) はTR 24731-1を発行し、 TR 24731-2に取り組んでいます。

TR 24731-1: C ライブラリの拡張 パート I: 境界チェック インターフェイス

WG14 は、より安全な C ライブラリ関数に関する TR に取り組んでいます。この TR は、多くの場合、バッファー長にパラメーターを追加することによって、既存のプログラムを変更することを目的としています。最新のドラフトはドキュメント N1225 にあります。根拠はドキュメント N1173 にあります。これはテクニカル レポート タイプ 2 になります。

TR 24731-2: C ライブラリの拡張 - パート II: 動的割り当て関数

WG14 は、より安全な C ライブラリ関数に関する TR に取り組んでいます。この TR は、バッファー長の追加パラメーターの代わりに動的割り当てを使用する新しいプログラムを対象としています。最新のドラフトはドキュメント N1337 にあります。これはテクニカル レポート タイプ 2 になります。

質問

  • TR24731-1 関数をサポートするライブラリまたはコンパイラを使用していますか?
  • もしそうなら、どのコンパイラまたはライブラリで、どのプラットフォームで使用されていますか?
  • これらの関数を使用するようにコードを修正した結果、バグが見つかりましたか?
  • 最も価値のある機能はどれですか?
  • 値がない、または負の値を提供するものはありますか?
  • 今後図書館を利用する予定はありますか?
  • TR24731-2 の作業を追跡していますか?
4

5 に答える 5

68

私はこれらのTRの開始以来(単一のTRであったとき)、これらのTRを声高に批評しており、私のソフトウェアでそれらを使用することは決してありませんでした。それらは原因に対処する代わりに症状を覆い隠し、同じ目標をはるかに効果的に達成できる既存の慣行を促進するのではなく、誤った安心感を提供するため、ソフトウェア設計に悪影響を与えると私は考えています。私は一人ではありません。実際、これらのTRを開発している委員会の外にいる1人の主要な支持者を知りません。

私はglibcを使用しているので、glibcの主任メンテナーであるUlrich Drepperがこのトピックについて述べているように、このナンセンスに対処する必要がないことを知っています。

提案されたsafe(r)ISO Cライブラリは、完全に発行するために対処できません。...プログラマーの生活をさらに困難にすることを提案しても、役に立たないでしょう。しかし、これはまさに提案されていることです。...それらはすべて、実行するためにより多くの作業を必要とするか、または単にばかげています。

彼はさらに、提案された関数の数に関する問題の詳細を説明し、glibcがこれをサポートすることは決してないことを他の場所で示しています。

オースティングループ(POSIXの保守を担当)は、TR、そのコメント、およびここで入手可能な委員会の回答について非常に批判的なレビューを提供しました。オースティングループのレビューは、TRの問題の多くを詳細に説明する非常に優れた仕事をしているので、ここでは個別の詳細には立ち入りません。

つまり、私はこれをサポートする、またはサポートする予定の実装を使用していません。これらの関数を使用する予定はなく、TRに正の値はありません。私は個人的に、TRが何らかの形でまだ生きている唯一の理由は、広範囲にわたる反対にもかかわらず、標準委員会を通じて物事を突っ込むことが非常に可能であることが最近証明されたMicrosoftによって強く押されているためだと信じています。これらの機能が標準化されたとしても、提案が数年前からあり、実際のコミュニティの支持を得ることができなかったため、広く使用されることはないと思います。

于 2008-12-16T22:59:57.390 に答える
31

質問に対する直接の回答

私はロバートの答えが好きですが、私が提起した質問についてもいくつかの見解があります.

  • TR24731-1 関数をサポートするライブラリまたはコンパイラを使用していますか?

    いいえ、私はしません。

  • もしそうなら、どのコンパイラまたはライブラリで、どのプラットフォームで使用されていますか?

    関数は MS Visual Studio (MS VC++ 2008 Edition など) によって提供されていると思いますが、それらを使用するように促す警告があります。

  • これらの関数を使用するようにコードを修正した結果、バグが見つかりましたか?

    まだ。そして、私のコードで多くのことが明らかになるとは思っていません。私が扱っている他のコードのいくつか - 多分。しかし、私はまだ確信していません。

  • 最も価値のある機能はどれですか?

    %n関数の printf_s() ファミリーが「 」形式指定子を受け入れないという事実が気に入っています。

  • 値がない、または負の値を提供するものはありますか?

    tmpfile_s()関数と関数はtmpnam_s()ひどい失望です。mkstemp()彼らは、TOCTOU (チェック時、使用時) の脆弱性がないことを確認するために、ファイルを作成して開くのと同じように機能する必要がありました。現状では、これら 2 つはほとんど価値がありません。

    strerrorlen_s()また、それはほとんど価値を提供しないと思います。

  • 今後図書館を利用する予定はありますか?

    私はそれについて2つの考えを持っています。標準 C ライブラリに TR 24731 の機能を実装するライブラリの作業を開始しましたが、正しく動作していることを実証するために必要な単体テストの量に悩まされました。それを続けるかどうかはわかりません。Windows に移植したいコードがいくつかあります (主に、すべてのプラットフォームでサポートを提供したいというひねくれた欲求からです。これは、数十年にわたって Unix 派生物に取り組んできました)。残念ながら、MSVC コンパイラからの警告なしにコンパイルするには、完全に信頼できる (慎重に使用した場合) 標準 C ライブラリ関数を使用して、MSVC が私のことを気にしないようにコードを塗りつぶす必要があります。そして、それは食欲をそそるものではありません。その期間に開発された 20 年分のシステムのほとんどに対処しなければならないのは十分に悪いことです。誰かの楽しみのアイデア (必要のないときに TR 24731 を採用させること) に対処しなければならないのは面倒です。それが、私がライブラリの開発を始めた理由の 1 つです。Unix と Windows で同じインターフェイスを使用できるようにするためです。でも、ここからどうなるかわかりません。

  • TR24731-2 の作業を追跡していますか?

    質問のデータを収集しているときに標準サイトに行くまで、私はそれを追跡していませんでした. asprintf()andvasprintf()関数はおそらく価値があります。私はそれらを使用します。メモリ ストリーム I/O 関数についてはよくわかりません。Cstrdup()レベルで標準化されたことは、大きな前進です。これは、パート 1 (境界チェック) インターフェースほど議論の余地がないように思えます。

全体として、パート 1 の「境界チェック インターフェイス」には納得できません。第 2 部「動的割り当て関数」のドラフトの資料の方が優れています。

それが私に任されていれば、パート 1 の行に沿って移動しますchar *が、文字列の先頭に a を返す C99 標準 C ライブラリのインターフェイス (たとえばstrcpy()and strcat()) を修正して、代わりに先頭へのポインターを返すと、新しい文字列の末尾にある null バイトへのポインターが返されます。これにより、いくつかの一般的なイディオム (文字列を別の文字列の末尾に繰り返し連結するなど) がより効率的になります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 
);

パラメーター

  • buffer - 出力の保存場所。
  • sizeOfBuffer - 出力用のバッファーのサイズ。
  • count - 書き込む最大文字数 (終端の null を含まない)、または _TRUNCATE。
  • format - フォーマット仕様。
  • argptr - 引数のリストへのポインター。

これは単に型マッピングの問題ではないことに注意してください。固定引数の数が異なるため、相容れません。また、'sizeOfBuffer' と 'count' の両方を使用することのメリットは、私には (おそらく標準化委員会にも) 不明です。同じ情報が 2 回あるように見えます (または、少なくとも、コードは通常、両方のパラメーターに同じ値で記述されます)。

scanf_s()同様に、およびその親戚 にも問題があります。Microsoftは、バッファー長パラメーターの型は(「サイズ パラメーターの型は 」ではなく、 「 unsigned」と明示的に述べています) と述べています。対照的に、附属書 K では、サイズ パラメータは型であり、これは(の別の名前ですが、より小さい)の制限されたバリアントです。したがって、 Microsoft C と標準 Cでは、コード呼び出しを別の方法で記述する必要があります。unsignedsize_trsize_tsize_trsize_tsize_tRSIZE_MAXSIZE_MAXscanf_s()

当初、条件付きコードを記述する必要なく、Windows と Unix でコードをクリーンにコンパイルする方法として、「安全な」関数を使用することを計画していました。Microsoft と ISO の機能が常に同じであるとは限らないため、これは失敗するので、あきらめるにはかなり時間がかかります。


vsnprintf()Visual Studio 2015における Microsoft の変更点

の Visual Studio 2015 ドキュメントではvsnprintf()、インターフェイスが変更されたことに注意してください。

Visual Studio 2015 および Windows 10 の UCRT 以降、vsnprintfは と同一ではなくなりました_vsnprintf。このvsnprintf関数は C99 標準に準拠しています。_vnsprintf下位互換性のために保持されています。

ただし、Microsoft のインターフェイスvsnprintf_s()は変更されていません。


Microsoft と Annex K の違いのその他の例

の C11 標準バリアントはlocaltime_s()、ISO/IEC 9899:2011 付属書 K.3.8.2.4 で次のように定義されています。

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

localtime_s()次のように定義された MSDN バリアントと比較して:

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

localtime_r()および次のように定義された POSIX バリアント:

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

C11 標準と POSIX 関数は、名前を除いて同等です。Microsoft 関数は、C11 標準と名前を共有していますが、インターフェイスが異なります。

違いのもう 1 つの例は、Microsoftstrtok_s()と Annex Kstrtok_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 つの引数があるのに対し、Annex K バリアントには 4 つの引数があることに注意してください。これは、Microsoft の引数リストがstrtok_s()POSIX のものと互換性があることを意味しますstrtok_r()— したがって、関数名を (例えばマクロによって) 変更すると、これらの呼び出しは事実上交換可能になります — しかし、標準 C (附属書 K) バージョンは、追加の引数で両方とは異なります。

Mac と Linuxでの宣言が異なるqsort_r()という質問には、 qsort_s()Microsoft によってqsort_s()定義されたものと TR24731-1 によって定義されたものについても議論されている回答があります — 繰り返しますが、インターフェイスは異なります。


ISO/IEC 9899:2011 — C11 規格

C11 標準 ( 2010 年 12 月の草案。最終的な標準ISO/IEC 9899:2011の PDF コピーを ANSI Web ストアから 30 米ドルで一度に入手できます) には、TR24731-1 機能がオプションとして含まれています。規格の一部。それらは、「情報」ではなく「規範」である附属書 K (境界チェック インターフェース) で定義されていますが、オプションです。

C11 標準には、TR24731-2 関数が含まれていませんvasprintf()。関数とその関連関数が本当に役立つ可能性があるため、これは悲しいことです。

簡単な要約:

  • C11 には TR24731-1 が含まれています
  • C11 には TR24731-2 が含まれていません
  • C18 は TR24731 に関する C11 と同じです。

C11の後継から附属書Kを削除する提案

Deduplicatorは、別の質問へのコメントで、ISO C 標準委員会 (ISO/IEC JTC1/SC22/WG14) の前に提案があると指摘しました。

これには、附属書 K 関数の現存する実装の一部への参照が含まれています — それらはどれも広く使用されていません (ただし、興味がある場合はドキュメントから見つけることができます)。

ドキュメントは次の推奨事項で終わります。

したがって、附属書 K を C 標準の次の改訂版から削除するか、非推奨にしてから削除することを提案します。

私はその勧告を支持します。

C18 規格は、附属書 K のステータスを変更しませんでした。附属書 K を完全に削除するのではなく、欠陥を修復して、いくつかの変更を行うことを提唱する論文N2336があります。

于 2008-12-17T07:43:09.330 に答える
7

さて、TR24731-2の略です。

はい、私はasprintf()/vasprintf()を glibc で見たときから使用してきました。そうです、私はそれらの非常に強力な支持者です。

なんで?
私が必要としているものを正確に提供してくれるからです: 強力で、柔軟で、安全で、(比較的) 使いやすい方法で、任意のテキストを新たに割り当てられた文字列にフォーマットします。

私はmemstream関数にも大いに賛成です: Like asprintf(), open_memstream()(not fmemopen()!!!) は、十分に大きなバッファーを割り当て、FILE*印刷を実行できるようにするため、印刷関数は、文字列に印刷されているかどうかを完全に認識できません。またはファイルであり、必要な容量を単純に忘れることができます。

于 2013-06-27T21:42:19.043 に答える
5

TR24731-1 関数をサポートするライブラリまたはコンパイラを使用していますか? もしそうなら、どのコンパイラまたはライブラリで、どのプラットフォームで使用されていますか?

はい、Visual Studio 2005 & 2008 (明らかに Win32 開発用)。

これらの関数を使用するようにコードを修正した結果、バグが見つかりましたか?

Linux、Windows、VxWorks、INtime、RTX、およびuItronなど、複数のプラットフォームで使用される安全な関数の独自のライブラリ(頻繁に使用する約15個のみ)を作成しました。安全な関数を作成した理由は次のとおりです。

  • 標準 C 関数の不適切な使用による多数のバグに遭遇しました。
  • TR 関数に渡される情報、または TR 関数から返される情報、または場合によってはそれらの POSIX 代替に満足できませんでした。

関数が作成されると、さらに多くのバグが発見されました。そうです、関数を使用する価値がありました。

最も価値のある機能はどれですか?

vsnprintf、strncpy、strncat のより安全なバージョン。

値がない、または負の値を提供するものはありますか?

fopen_s および同様の関数は、個人的にはほとんど価値がありません。fopen が NULL を返す場合は問題ありません。関数の戻り値は常にチェックする必要があります。誰かが fopen の戻り値を無視した場合、何が彼らに fopen_s の戻り値をチェックさせるのでしょうか? fopen_s が特定のコンテキストで役立つ、より具体的なエラー情報を返すことを理解しています。しかし、私が取り組んでいることについては、これは問題ではありません。

今後図書館を利用する予定はありますか?

現在、独自の「安全な」ライブラリ内で使用しています。

TR24731-2 の作業を追跡していますか?

いいえ。

于 2009-05-15T16:10:05.173 に答える