strerror を使用できないのはなぜですか?

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

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


strerror それ自体は安全ではありません。スレッド化する前の昔は、それはまったく問題ではありませんでした。スレッドでは、2 つ以上のスレッドが strerror を呼び出すことができます 返されたバッファを未定義の状態のままにします。シングルスレッド プログラムの場合、 strerror を使用しても害はありません。 DLL 内のすべてのアプリの共通メモリなど、libc で奇妙なゲームをプレイしている場合を除きます。

これに対処するために、同じ機能への新しいインターフェースがあります:

int strerror_r(int errnum, char *buf, size_t buflen);

呼び出し元がバッファー スペースとバッファー サイズを提供することに注意してください。これで問題は解決します。シングルスレッドのアプリケーションであっても、それを使用したほうがよいでしょう。多少の痛みはありません。より安全な方法で行うことに慣れた方がよいでしょう。

注:上記のプロトタイプは、strerror_r() の POSIX 仕様からのものです。 .プラットフォームごと、またはコンパイラ オプションまたは #define によって異なる場合があります。 シンボル。たとえば、GNU は #define に応じて、それまたは独自のバージョンを利用可能にします。 .


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 以外のエラー コードを指定できます 、また、いくつかのデバッグ情報も表示します。必要に応じて調整できます。