ホームページ  >  記事  >  バックエンド開発  >  TIL CAnnex K は存在しますが、使用しないでください

TIL CAnnex K は存在しますが、使用しないでください

DDD
DDDオリジナル
2024-11-03 13:58:03338ブラウズ

TIL CAnnex K exists but you shouldn

付録 K は技術名です。その他の一般的なキーワードは、__STDC_LIB_EXT1__ および __STDC_WANT_LIB_EXT1__ です。付属書 K は、sprintf_s() や scanf_s() などの「安全な」_s サフィックスを定義します。

Annex K (2015) と境界チェックのフィールド エクスペリエンスもチェックしてください - cppreference.com の技術文書。

目標

_s() 関数の意味は何ですか?これらは、引数に「ストリームが null、文字列が null、bufsz が 0、またはバッファが指定された長さを超えて境界外に書き込む場合に制約ハンドラーを呼び出す」などの不変条件がないかどうかをチェックします。それは良いアイデアだと思いますよね?うん!そうです!

要点は、次のことができる/できるということです:

#define __STDC_WANT_LIB_EXT1__ 1
#include ade979de5fc0e1ca0540f360a64c230b

int main() {
  printf_s("Hello %s!\n", "Alan Turing");
  return 0;
}

これは、__STDC_WANT_LIB_EXT1__ を使用しない通常の方法と比較してどうですか?

幸せな道

FILE *file = fopen("hello.txt", "r");
// file is OK.
FILE *file;
errno_t err = fopen_s(&file, "hello.txt", "r");
// file is OK

悲しい道

FILE *file = fopen("notexist.txt", "r");
// file is NULL, errno is set.
FILE *file;
errno_t err = fopen_s(&file, "notexist.txt", "r");
// file is NULL, err is set.

悪いパス

FILE *file = fopen(NULL, NULL);
// idk.
FILE *file;
errno_t err = fopen_s(&file, NULL, NULL);
// Constraint violated. Abort with message.

はい、ファイルにログを記録するだけで何も起こらなかったかのように続行するように制約ハンドラーをカスタマイズできます。

set_constraint_handler_s(ignore_handler_s);
set_constraint_handler_s(abort_handler_s);
set_constraint_handler_s(my_awesome_handler);

通常の fopen() が、異なるレベルのエラーの悪さを示すために同じ戻り値 (おそらく異なる errno) を持っていることに注目してください。それがこの fopen_s() が改善しようとしていたことです。少なくとも、それが私の解釈です。私はこれを Rust のパニック!() と返された Resulte1c7801d19b137084b3a257467b07ace のようなものだと考えています。また、strcpy_s() や gets_s() などの dest バッファのオーバーフローを避けるために size_of_dest 引数を提供することで、一部のバッファ オーバーフロー攻撃を阻止するのにも役立つと思われます。

char* gets( char* str ); // (removed in C11)
char* gets_s( char* str, rsize_t n ); // (since C11, annex K)

改行文字が見つかるかファイルの終わりが発生するまで、str が指す文字配列に stdin を読み込みます。 NULL 文字は、配列に読み取られた最後の文字の直後に書き込まれます。改行文字は破棄されますが、バッファには保存されません。

gets() 関数は境界チェックを実行しないため、この関数はバッファ オーバーフロー攻撃に対して非常に脆弱です。これは安全に使用できません (標準入力に表示できる内容が制限されている環境でプログラムが実行されない限り)。このため、この関数は C99 標準の 3 番目の修正案で非推奨となり、C11 標準では完全に削除されました。 fgets() と gets_s() が推奨される代替品です。

警告:gets() は決して使用しないでください。

// BAD
char buffer[1000];
gets(buffer);
// ⚠️ Could write >1000 chars to `buffer`!
// GOOD
char buffer[1000];
gets_s(buffer, sizeof(buffer));
// This will stop at 1000 chars.

_s() 関数は、バッファ オーバーフローが発生する可能性のある一般的な場所を停止するのに非常に優れているようです。

問題

どこでも実装されているわけではありません。 _s() 関数は、GNU の glibc のような libc 実装では使用できない 拡張です。他にも、マルチスレッドに対して人間工学的ではないことや、strcpy_s() などで sizeof(dest) の代わりに sizeof(src) を実行するというよくある間違いなどの小さな問題がありますが、可用性の問題に比べれば、それらはすべて取るに足らないものです。

私が見つけることができるオンライン情報のほとんどは、MSVC が Annex K を実装している唯一の主要なコンパイラ/libc であることを示しているようです。

これらの派手な _s() 関数がコードのコンパイルに必要な場所にあるわけではないことを考えると、次のようなコードを記述する必要があります。

#define __STDC_WANT_LIB_EXT1__ 1
#include ade979de5fc0e1ca0540f360a64c230b

int main() {
  printf_s("Hello %s!\n", "Alan Turing");
  return 0;
}

...strlen_s()、fopen_s()、または strcpy_s() を実行したいすべてのインスタンスに対して。それは正気を失うには良い方法です。

基本的な printf() と strcpy() を実行するためだけにプラットフォームに依存するコードを作成するつもりはないことは明らかです。しかし、#ifdef __STDC_LIB_EXT1__ #else のものをすべてライブラリにラップするのはどうでしょうか?

簡単な Google 検索で見つけた、有望そうなライブラリが 2 つありました。

    safec: Safe C ライブラリ Web サイト GitHub ページ ⭐335
  • sbaresearch/slibc: C11 Annex K「境界チェックインターフェイス」ISO/IEC 9899:2011 ⭐14
  • の実装
つまり... _s() 関数を使用したい (またはセキュリティ関連で使用する必要がある) が、MSVC だけに限定したくない場合は、これらの ☝ ライブラリのいずれかを使用できます。

?詳細については、Annex K (2015) と境界チェックによるフィールド エクスペリエンス - cppreference.com 技術ドキュメントを参照してください。

以上がTIL CAnnex K は存在しますが、使用しないでくださいの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。