Search code examples
clinuxgcclibc

strerrorname_np and strerrordesc_np cause seg fault on linux gcc


I have been reading through info libc, and in section 2.3 "Error Reporting - Error Messages" it mentions the following two functions:

-- Function: const char * strerrorname_np (int ERRNUM)

| MT-Safe | AS-Safe | AC-Safe | *Note POSIX Safety Concepts::.

This function returns the name describing the error ERRNUM or
‘NULL’ if there is no known constant with this value (e.g >"EINVAL"
for ‘EINVAL’).

This function is a GNU extension, declared in the header file
‘string.h’.

-- Function: const char * strerrordesc_np (int ERRNUM)

| MT-Safe | AS-Safe | AC-Safe | *Note POSIX Safety Concepts::.

This function returns the message describing the error ERRNUM or
‘NULL’ if there is no known constant with this value (e.g >"Invalid
argument" for ‘EINVAL’).  Different than ‘strerror’ the returned
description is not translated.

but these functions are not working on my Linux (Ubuntu) machine as expected. They compile but result in a warning that I am attempting to use a type 'int' where a 'char *' belongs. Further, when the program is run it results in a seg fault.

Here is some sample code where I intentionally misuse fopen to generate an errno and then attempt to use the above functions as described:

#include <errno.h>  /* errno  */
#include <stdio.h>  /* printf */
#include <string.h> /* <-- functions should be here! */

void error_reporting_example(void)
{
    /* to generate an error, I'll pass fopen a bad flag */
    FILE * file = fopen("some_file", "bad_flags");
    if(file == NULL)
    {
        int errno_saved = errno;
        printf("ERROR: fopen failed with errno = %d\n\tError Name: %s\n\tError Description: %s\n", 
                errno_saved, 
                strerrorname_np(errno_saved),
                strerrordesc_np(errno_saved));
    }
}

the resulting output is

$ ./test
ERROR: fopen failed with errno = 22
Segmentation fault (core dumped)

Thinking that I had either outdated documentation or an incompatible libc, I verified the existence of the function prototyptes in string.h

$ grep -rns /usr/include -e 'strerrordesc_np'
/usr/include/string.h:450:extern const char *strerrordesc_np (int __err) __THROW;
$ grep -rns /usr/include -e 'strerrorname_np'
/usr/include/string.h:452:extern const char *strerrorname_np (int __err) __THROW;

and I ran gcc with the -H flag to list header files used when compiling the file in question to verify the inclusion of /usr/include/string.h


Solution

  • It's more obviously spelled out in the man page than in the info docs, but since strerrordesc_np() and strerrorname_np() are GNU extensions, the _GNU_SOURCE feature test macro needs to be defined before including any headers in order to make those functions available for use.

    If you'd included the complete warnings you got when compiling in the question, it should include ones about implicit declarations of those functions. Without a prototype, the compiler assumes they return int's, and returning a pointer instead is what ends up ultimately causing undefined behavior manifesting as a segfault.

    Adjust your source so the very first line is

    #define _GNU_SOURCE
    

    and it should work as intended.