35

いくつかのコードを Windows に移植していますが、Microsoft コンパイラ (Visual C++ 8) から、それstrerror()は安全ではないと言われています。

Microsoft のすべての安全な文字列に関する煩わしさは別として、非推奨の関数のいくつかが危険であることは実際にわかります。しかし、何が問題なのか理解できませんstrerror()。コード ( int) を受け取り、対応する文字列を返すか、そのコードが不明な場合は空の文字列を返します。

危険はどこにありますか?

Cに良い代替手段はありますか?

C ++に良い代替手段はありますか?

[編集]

いくつかの良い答えがあり、一部の実装は実際に共通の共有バッファーに書き込むのに十分クレイジーである可能性があることを理解しました-シングルスレッド内での再入可能性は安全ではありません。スレッド間は気にしないでください! -私の質問は、「なぜそれを使用できないのか、代替手段は何ですか?」ではなくなります。「Cおよび/またはC ++に適切で簡潔な代替手段はありますか?」

前もって感謝します

4

7 に答える 7

31

strerrorスレッドセーフではないため、非推奨です。strerror他の並行スレッドによって上書きされる可能性がある内部静的バッファーで動作します。と呼ばれる安全なバリアントを使用する必要がありますstrerror_s

安全なバリアントでは、バッファーに書き込む前にバッファーが十分な大きさであることを検証するために、バッファー サイズを関数に渡す必要があります。これにより、悪意のあるコードの実行を可能にするバッファー オーバーランを回避できます。

于 2009-05-22T23:02:43.433 に答える
17

いくつかの良い答えがあり、いくつかの実装が実際に共通の共有バッファーに書き込むのに十分クレイジーである可能性があることを理解しました-シングルスレッド内での再入可能性は安全ではありません。スレッド間は気にしないでください! -私の質問は、「なぜそれを使用できないのか、代替手段は何ですか?」ではなくなります。「Cおよび/またはC ++に適切で簡潔な代替手段はありますか?」

Posix では が指定されstrerror_r()ており、Windows では を使用できますstrerror_s()。これは少し異なりますが、目的は同じです。私はこれをします:

#define BAS_PERROR(msg, err_code)\
  bas_perror(msg, err_code, __FILE__, __LINE__)

void bas_perror (const char* msg, int err_code, const char* filename,
                 unsigned long line_number);


void
bas_perror (const char* usr_msg, int err_code, const char* filename,
            unsigned long line_number)
{
  char sys_msg[64];

#ifdef _WIN32
  if ( strerror_s(sys_msg, sizeof sys_msg, err_code) != 0 )
  {
    strncpy(sys_msg, "Unknown error", taille);
    sys_msg[sizeof sys_msg - 1] = '\0';
  }
#else
  if ( strerror_r(err_code, sys_msg, sizeof sys_msg) != 0 )
  {
    strncpy(sys_msg, "Unknown error", sizeof sys_msg);
    sys_msg[sizeof sys_msg - 1] = '\0';
  }
#endif

  fprintf(stderr, "%s: %s (debug information: file %s, at line %lu)\n",
          usr_msg, sys_msg, filename, line_number);
}

私がこの関数を書いたのは、Posix スレッド関数は を変更せずerrno、代わりにエラー コードを返すためです。したがって、この関数は基本的に と同じですがperror()、 以外のエラー コードを提供できる点と、errnoデバッグ情報も表示できる点が異なります。必要に応じて調整できます。

于 2009-05-23T10:59:52.463 に答える
5

strerror()関数の次の呼び出しで変更される可能性があるため、返される文字列に依存することはできません。その場合、以前に返された値は廃止される可能性があります。特にマルチスレッド環境では、アクセス時に文字列が有効であることを保証できません。

これを想像してください:

Thread #1:
char * error = strerror(1);
                                    Thread #2
                                    char * error = strerror(2);
printf(error);

の実装によってはstrerror()、このコードはエラー コード 1 ではなく、エラー コード 2 のエラー コードを出力します。

于 2009-05-22T23:03:36.693 に答える
-1

Microsoft の理由はわかりませんが、strerror が const 以外の char * を返すことに注意してください。これは、メッセージを変更する前に、陽気ないたずら者が strerror を呼び出した可能性があることを意味します。

于 2009-05-22T23:04:14.570 に答える