errnoのC / C ++マルチスレッドの処理とセキュリティの問題

C言語では、エラー・コードにグローバル変数errnoを格納するために、私は誰もが精通していると信じています。混乱と正常戻り値を防止するために、システムは、一般的に直接にerrnoにはerrnoという名前のグローバル変数に戻るにエラーコードが、エラーコード(整数値、異なる値が異なる意味を表す)を呼び出しませんエラーメッセージは、<ERRNO.H>ファイルで定義された異なる値を表します。システムコールやライブラリ関数の呼び出しが失敗した場合、プログラムをデバッグする重要な方法である、読んでerrnoに手続き上のエラーの値を示唆し、問題の原因を特定することが可能です。

perrorはおよびstrerror関数を使用すると、簡単にエラーの詳細を表示することができます。どこで:

  • perrorは<stdio.hの>、エラーコードおよび説明メッセージを印刷するために定義されました。
  • strerror <string.hの>で定義され、記述に対応するエラーコードを取得するためのメッセージ。

これは、最初のエラー番号を呼び出す前にクリアする必要があります。

C言語で、またはシステムコールライブラリ関数が正しく行われている場合は、errnoの値はクリアされません。言い換えれば、errnoの値は唯一のランタイムライブラリ関数呼び出しが成功したときにエラーが発生したライブラリ関数の呼び出しに設定され、errnoの値はもちろん、イニシアチブが0に設定されてなりません、変更されません。正確には、このため、実際のプログラミングエラーの診断に多くの問題があるでしょう。

例えば:

/// @file main.cpp
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(void)
{
    /*调用errno之前必须先将其清零*/
    errno=0;
    FILE *fp = fopen("test.txt","r");
    if(errno!=0)
    {
        printf("errno值: %d\n",errno);
        printf("错误信息: %s\n",strerror(errno));
    }
    fp = fopen("main.cpp","r");
    if(errno!=0)
    {
        printf("errno值: %d\n",errno);
        printf("错误信息: %s\n",strerror(errno));
    }
    fclose(fp);
    return 0;
}

出力:

$ g++ main.cpp -o main
$ ./main
errno值: 2
错误信息: No such file or directory
errno值: 2
错误信息: No such file or directory

再定義エラー番号を避けてください。

ISO CとPOSIXによって標準シンボルに定義されているerrnoを、のために。以前、POSIX標準は、これまでのerrnoこのフォーム「のextern int型のerrno」と定義されますが、今どのようにこの比較的まれな定義にerrnoこれは致命的であるマルチスレッドの形をとるので、それがあります。

スレッドは、エラーが発生しなかったが、次にBスレッド、いくつかのエラーのエラー番号の値を変更し、それはエラー番号を検出したときにされている:マルチスレッド環境では、errnoに変数は、それが以下につながる可能性ように、複数のスレッドで共有されていますスレッドBの値も考えるだろうときにエラーが発生しました。

私たちは、マルチスレッド環境では、複数のスレッドがプロセスのアドレス空間を共有していることを知っているので、各スレッドが別のスレッドにスレッドの干渉を避けるために、独自のローカルのerrnoを持っている必要があります。実際には、コンパイラによって、今ではほとんどの部分は、各弦のスレッド間のエラーの原因が変化しないことを確認するために、スレッドローカル変数の形で実現するためにerrnoに設定されています。

たとえば、Linux GCCコンパイラの場合には、標準のerrno「/usr/include/errno.h」の定義は、次のように:

/* Get the error number constants from the system-specific file.
   This file will test __need_Emath and _ERRNO_H.  */
#include <bits/errno.h>
#undef   __need_Emath
#ifdef   _ERRNO_H
/* Declare the `errno' variable, unless it's defined as a macro by bits/errno.h.  This is the case in GNU, where it is a per-thread variable.  This redeclaration using the macro still works, but it will be a function declaration without a prototype and may trigger a -Wstrict-prototypes warning.  */
#ifndef   errno
extern int errno;
#endif

ここで、errnoが「/usr/include/bits/errno.h」ファイルに具体次のとおりです。

# ifndef __ASSEMBLER__
/* Function to get address of global 'errno' variable.  */
extern int *__errno_location (void) __THROW __attribute__ ((__const__));
# if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads,errno is a per-thread value.  */
# define errno (*__errno_location ())
# endif
# endif /* !__ASSEMBLER__ */
# endif /* _ERRNO_H */

このように、で "のextern int型* __(無効)errno_location、__ THROW__attribute __((__ const__));" と "の#defineのerrno(* __ errno_location())" に定義されているので、各スレッドは、独自のerrnoを、持っていることに関係なく、どのスレッドのerrnoにある変更するにはスレッドセーフを達成するために、独自のローカル変数を変更します。

ファイルストリームエラーをチェックerrnoを使用しないでください。

既にPOSIX標準で、前に説明したように、errno値は、エラーが発生したかどうかのfopen関数を呼び出すことによって確認することができます。ただし、特定のファイルストリーム操作は、エラーがファイルストリームのエラーチェックのためにerrnoを使用できず、ferror関数機能を使用する必要があるかどうかを確認してください。次のサンプルコード:

int main(void)
{
    FILE* fp=NULL;
    /*调用errno之前必须先将其清零*/
    errno=0;
    fp = fopen("Test.txt","w");
    if(fp == NULL)
    {
        if(errno!=0)
        {
            /*处理错误*/
        }
    }
    else
    {
        /*错误地从fp所指定的文件中读取一个字符*/
        fgetc(fp);
        /*判断是否读取出错*/
        if(ferror(fp))
        {
            /*处理错误*/
            clearerr(fp);
        }
        fclose(fp);
        return 0;
    }
}
公開された257元の記事 ウォン称賛13 ビュー60000 +

おすすめ

転載: blog.csdn.net/LU_ZHAO/article/details/105119476
おすすめ