0

If what I am trying to do is not a good idea or not supported, please feel free to let me know. I am trying to use various system libraries (libc.so.6, libpthread.so.0, etc.) for an API. The API will be calling into these libraries to access open(), close(), etc...

I'm not sure how to handle errno on failures, returning -1, rather than returning errno directly. When I make a call to close() in libc.so.6, it returns -1 on failure, so I can detect an error occurred. However, I cannot seem to find any mechanism in libc that allows me to query the current value of errno that may have been set by a previous function call in the same thread. This isn't a problem when calling pthread functions because they return errno's value directly, and I can work with this.

Is there a way to determine the current value of errno for a given thread following the execution of a function that would have set errno (such as close()) using a library call of some kind?

Possible solutions:

I could write a wrapper library that calls close(), etc... queries errno in an error state, and returns errno directly, but I'm trying to avoid having to include custom libraries that would have to be included with the API.

If there is a way to call a standard library, that would be ideal.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Ryan
  • 1
  • 2
    The 'variable' `errno` is thread-local, not global. – Jonathan Leffler Jan 18 '17 at 22:26
  • 2
    Not clear what you are asking. `errno` is accessible globally per thread. So you don't need any library function to get it's value. Simply: `r = some_libc_function(); if (r==-1) last_errno = errno;` – kaylum Jan 18 '17 at 22:26
  • Thanks for the replies. I probably should have clarified further that I am accessing these libraries from an environment that provides an interface for calling libraries, but does not have a way to compile code alongside these library calls, such as including and accessing errno directly as a variable. This is why I'm trying to see if there is any way to access errno if I have not written code specifically to do so. Not sure if that makes sense. – Ryan Jan 18 '17 at 22:38
  • 3
    @Ryan: In that case you probably need to make an additional stub library containing a `get_errno` function or similar that simply returns the value (or address) of `errno`. Alternatively you could use the `__errno_location` function that's the backend of `errno` on glibc, but this would not be a portable design. – R.. GitHub STOP HELPING ICE Jan 18 '17 at 22:43
  • Love the stub idea @_R.. So, Ryan, why can't you get errno by its address? What about `dlsym()`? Or I guess the problem there is you need the already opened library in the image's runtime list... – clearlight Jan 18 '17 at 23:13
  • @clearlight: `errno` is a thread-local symbol, not a global symbol, so it doesn't have an address as such -- just an offset in the thread local section. For historical reasons, it is often not implemented simply as a thread-local symbol called `errno`, so you can't just declare that, even if your compiler supports thread-local symbols. – Chris Dodd Jan 18 '17 at 23:16
  • @ChrisDodd, so if it's in TLS are can it be inferred that there's some non-ugly way to access it without a stub function? – clearlight Jan 18 '17 at 23:19
  • @clearlight: depends on C library. For example, Solaris libc does this: `#define errno (*(___errno()))` – myaut Jan 18 '17 at 23:20
  • @R.. Thanks for the stub idea. I gave this a try by forcing close() to generate an error (gave it an fd of -1) and then used __errno_location to get the errno pointer. Then deref'ing this address returned a value of 9 (EBADFD), which is what I expected. I understand this isn't portable, so I'll need to look further to see if this will be an issue for my API, but at the moment it does what I need. – Ryan Jan 18 '17 at 23:28
  • @ChrisDodd: Formally, `errno` is a macro, not an external object of any sort, so you can't expect there to be a symbol for it. Whether `errno` has an address is an open question: see http://stackoverflow.com/questions/12945486/is-errno-legal-c – R.. GitHub STOP HELPING ICE Jan 19 '17 at 00:58
  • @R: `errno` might be a macro, or it might not be -- different implementations differ. You can rely on it being a single lvalue for any particular thread, so you can get the address of it for a thread, that address will be stable for that thread. – Chris Dodd Jan 19 '17 at 01:04

1 Answers1

0

errno is not a global per process variable (as it used to be) in a multithread environment like linux, there is a different errno pseudovariable per thread (actually errno is a macro defined in #include <errno.h>). Answering your question, the best and easiest way to save the errno from a previous system call is to make a copy of errno as soon as the system call finishes. You can even make a wrapper around your system calls to store errno values in a circular buffer so you can get the last, previous to last, and so on, up to some fixed value. As storing all those values needs some amount of memory, no provision in the system for it has been called. Also, the errno value is something associated to the last system call made by one thread, so as you have to decide how and when you do a system call, you have also the possibility to decide if you want to store how and when the value of the error.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31