web-dev-qa-db-ja.com

TR 24731の「安全な」機能を使用していますか?

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の作業を追跡していますか?
71

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

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

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

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

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

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

64
Robert Gamble

質問への直接回答

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

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

    いいえ、しません。

  • もしそうなら、どのコンパイラまたはライブラリとどのプラットフォーム上にありますか?

    これらの機能はMSVisual Studio(MS VC++ 2008 Editionなど)によって提供されていると思いますが、使用を促す警告があります。

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

    未だに。そして、私は私のコードで多くを明らかにすることを期待していません。私が使用している他のコードのいくつか-多分。しかし、私はまだ確信していません。

  • どの機能が最も価値がありますか?

    Printf_s()ファミリーの関数が「_%n_」フォーマット指定子を受け入れないという事実が気に入っています。

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

    tmpfile_s()関数とtmpnam_s()関数はひどい失望です。彼らは本当にmkstemp()のように機能する必要がありました。これは、ファイルを作成して開き、TOCTOU(time-of-check、time-of-use)の脆弱性がないことを確認します。現状では、これら2つはほとんど価値を提供しません。

    また、strerrorlen_s()はほとんど価値がないと思います。

  • 将来、ライブラリを使用する予定はありますか?

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

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

    質問のデータを収集しながら標準サイトにアクセスするまで、追跡していませんでした。 asprintf()およびvasprintf()関数はおそらく価値があります。私はそれらを使用します。メモリストリームのI/O機能についてはよくわかりません。経営幹部レベルでstrdup()を標準化することは、大きな前進となるでしょう。これは、パート1(境界チェック)インターフェイスよりも物議を醸すものではないようです。

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

自分次第だとしたら、パート1の行に沿っていくらか移動しますが、文字列の先頭に_char *_を返すC99標準Cライブラリのインターフェイスも修正しました(例:strcpy()およびstrcat())。これにより、先頭へのポインタを返す代わりに、新しい文字列の末尾のnullバイトへのポインタが返されます。これにより、いくつかの一般的なイディオム(文字列を別の文字列の末尾に繰り返し連結するなど)がより効率的になります。これは、strcat()を繰り返し使用するコードによって示される2次動作を回避するのが簡単になるためです。置換により、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-書き込む最大文字数(終了ヌルを含まない)、または_TRUNCATE。
  • format-フォーマット仕様。
  • argptr-引数のリストへのポインタ。

これは単に型マッピングの問題ではないことに注意してください。固定引数の数が異なるため、調整できません。また、「sizeOfBuffer」と「count」の両方を持つことの利点が私には(そしておそらく標準委員会にも)わかりません。 2回同じ情報のように見えます(または、少なくとも、コードは通常、両方のパラメーターに対して同じ値で記述されます)。

同様に、scanf_s()とその親戚にも問題があります。 Microsoft は、バッファ長パラメータのタイプがunsignedであることを示しています(「サイズパラメータは_size_t_ではなくunsignedタイプであると明示的に述べています)。対照的に、Annex Kでは、サイズパラメータはタイプ_rsize_t_であり、これは_size_t_の制限付きバリアントです(_rsize_t_は_size_t_の別名ですが、_RSIZE_MAX_は_SIZE_MAX_)よりも小さいです。したがって、ここでも、scanf_s()を呼び出すコードは、MicrosoftCとStandardCでは異なる方法で記述する必要があります。

もともと、条件付きコードを記述せずに、WindowsとUnixでコードをクリーンにコンパイルする方法として「safe」関数を使用することを計画していました。 MicrosoftとISOの機能が常に同じであるとは限らないため、これは無効になっているため、あきらめる時期がかなり来ています。


Visual Studio2015でのMicrosoftのvsnprintf()の変更

vsnprintf() のVisual Studio 2015ドキュメントでは、インターフェイスが変更されたことが記載されています。

Visual Studio2015およびWindows10のUCRT以降、vsnprintfは__vsnprintf_と同一ではなくなりました。 vsnprintf関数はC99標準に準拠しています。 __vnsprintf_は、下位互換性のために保持されています。

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


MicrosoftとAnnexKの違いの他の例

localtime_s()のC11標準バリアントは、ISO/IEC 9899:2011 AnnexK.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);
_

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

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

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

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

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


ISO/IEC 9899:2011 — C11標準

C11規格( 2010年12月ドラフト ;一度にPDF最終規格のコピー ISO/IEC 9899:2011 =、ANSI Webストアから30米ドル)には、標準のオプション部分としてTR24731-1関数が含まれています。これらは、「情報」ではなく「標準」である付録K(境界チェックインターフェイス)で定義されています。 'ですが、オプションです。

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

簡単な要約:

  • C11にはTR24731-1が含まれています
  • C11にはTR24731-2は含まれていません
  • C18はC11w.r.tTR24731と同じです。

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

重複排除者コメント で指摘されたISO C標準委員会(ISO/IEC JTC1/SC22/WG14)の前に提案があるという別の質問

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

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

したがって、Annex KをC標準の次のリビジョンから削除するか、非推奨にしてから削除することをお勧めします。

私はその推薦を支持します。

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

28

さて、スタンドfor TR24731-2:

はい、私はglibcでそれらを見て以来、asprintf()/vasprintf()を使用してきました。そして、はい、私はそれらを非常に強く支持しています。

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

私もmemstreamsに大いに賛成です:asprintf()のように、open_memstream()fmemopen() !!!ではありません)はあなたに十分な大きさのバッファーを割り当て、あなたにFILE*印刷を行うため、印刷機能は文字列に印刷するのかファイルに印刷するのかを完全に認識できず、必要なスペースの量という質問を忘れることができます。

7
cmaster

いいえ、これらの関数はまったく役に立たず、コードの記述を促進する以外の目的はないため、Windowsでのみコンパイルされます。

snprintfは(正しく実装されている場合)完全に安全であるため、snprintf_sは無意味です。 strcat_sはデータを破棄しますバッファがオーバーフローした場合(連結された文字列をクリアすることにより)。物事がどのように機能するかを完全に知らない例は他にもたくさんあります。

本当に便利な関数はBSDstrlcpyとstrlcatです。しかし、MicrosoftとDrepperはどちらも、自分たちの利己的な理由でこれらを拒否し、あらゆる場所のCプログラマーを苛立たせています。

5
user3080602

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の作業を追跡していますか?

番号。

5
Kevin