C / C ++ multi-threaded processing and security issues of errno

In the C language, for storing error codes global variable errno, I believe everyone is familiar with. To prevent confusion and normal return value, the system generally does not directly call returns an error code, but the error code (an integer value, different values ​​represent different meanings) into a global variable named errno in, errno error messages represent different values ​​defined in <errno.h> file. If a system call or library function call fails, it is possible to determine the cause of the problem, suggesting that the value of errno procedural error by reading, which is an important method of debugging a program.

With perror and strerror function, you can easily view the details of error. among them:

  • perror defined in <stdio.h>, an error code and for printing description message;
  • strerror defined in <string.h>, a message for acquiring the error code corresponding to the description;

It must first be cleared before calling errno.

In the C language, or if the system call library functions are performed correctly, then the value of errno is not cleared. In other words, the value of errno will only be set at a library function call error occurs when the runtime library function call is successful, the value of errno is not modified, of course, will not take the initiative is set to 0. Precisely because of this, there will be many problems in the actual programming error diagnostics.

for example:

/// @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;
}

Output:

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

Avoid redefine errno.

For errno, which is a standard by the ISO C and POSIX defined symbols. Earlier, POSIX standard will ever errno is defined as "extern int errno" this form, but now define how this relatively rare, it is because errno This takes the form of multithreading is fatal.

In a multithreaded environment, errno variable is shared by multiple threads, so that it may lead to the following: A thread is changed errno value of some errors, then thread B, although no errors occurred, but when it detects errno when the value of the thread B will also think they error has occurred.

We know that in a multithreaded environment, multiple threads share the process address space, and therefore requires that each thread must have their own local errno to avoid another thread a thread interference. In fact, now the most part by the compiler are set errno to achieve in the form of thread local variables to ensure the cause of the error between each string thread does not change.

For example, in the case of Linux GCC compiler, the definition of the standard errno "/usr/include/errno.h" as follows:

/* 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

Wherein, errno embodied in "/usr/include/bits/errno.h" file is as follows:

# 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 */

Thus, by "extern int * __ errno_location (void), __ THROW__attribute __ ((__ const__));" and "#define errno (* __ errno_location ())" is defined, so that each thread has its own errno, regardless of which thread to modify errno are to modify their own local variables, so as to achieve thread-safe.

Avoid using errno check the file stream error.

As already explained before, in the POSIX standard, errno values ​​can be checked by calling the fopen function whether an error occurred. However, the specific file stream operations to check whether the error must be used ferror function, without being able to use errno for file stream error checking. The following sample code:

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;
    }
}
Published 257 original articles · won praise 13 · views 60000 +

Guess you like

Origin blog.csdn.net/LU_ZHAO/article/details/105119476