Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't errno's value be printed?

Tags:

c

gdb

errno

I am looking at the following code in an SO "Low Quality" post to make sure the sample works, and my question is why can't I print errno's value?

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(){
    FILE *fp;
    errno = 0;
    fp=fopen("Not_exist.txt","r");
    if(fp == NULL && errno == ENOENT)
        perror("file not exist");
    return 0;
}

Here is what happens when I try to print the value:

(gdb) p errno
Cannot find thread-local variables on this target
(gdb)

I can print fp's value just fine. As you would expect it's value is 0x00.

I looked at /usr/include/errno.h and a lot of the other include files included as part of errno.h, and I cannot figure out how errno is defined. Any pointers or help would be appreciated. I'm just curious about it; nothing is broken.

Thank you.

like image 502
octopusgrabbus Avatar asked Jul 15 '12 21:07

octopusgrabbus


3 Answers

The errno variable is kind of an odd duck. Because most runtime libraries these days support threads, there can't be just one errno variable. If there were, then two threads could do things at the same time that both set the errno value, and great confusion would ensue.

Runtime libraries do various tricks to avoid this problem. For example, one might do something like:

#define errno __get_errno()

where references to errno actually call the internal __get_errno() function, which returns the correct error number value for the current thread. The disadvantage of this method is it prevents assignment to errno, such as errno = 0; (which some code might do). Runtime libraries will usually choose a more sophisticated approach.

Some runtime libraries (like the one you're using, I suppose) can declare a special type of "thread-local variable" which can have a different value on each thread. It sounds like your debugger on your system can't display that kind of variable.

like image 164
Greg Hewgill Avatar answered Nov 02 '22 12:11

Greg Hewgill


In my Ubuntu installation, I have the following section in bits/errno.h:

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

That said, errno is not necessarily a variable. For various reasons you may want to have a function returning the error value for you rather than a simple extern int.1 That is why you can't print its value using GDB.

1of course, as you can see the function call should return the pointer to the actual variable and the errno macro would dereference it.

like image 43
Shahbaz Avatar answered Nov 02 '22 13:11

Shahbaz


As others have said, errno is not a variable that gdb can print. But gdb can evaluate functions, and __errno_location() returns a pointer to `errno'. The only thing we need to do then, is to call the function and dereference the restult:

(gdb) p *__errno_location()

And that's it.

like image 6
Rptx Avatar answered Nov 02 '22 12:11

Rptx