Re: errno/strerror() Observations

From: Paul Pluzhnikov (ppluzhnikov-nsp_at_charter.net)
Date: 04/07/05


Date: Wed, 06 Apr 2005 20:20:14 -0700

Josh Birnbaum <engineer@noorg.org> writes:

>> Try commenting it out and see if the problem goes away.
>
> I've done this and I still see the problem.

Well, something resets the errno ...

> This works fine under IRIX but fails under Linux. I'd like to
> find out why.

Hardware watchpoints to the rescue.

On x86, you can set a breakpoint on a memory location, and have
gdb stop when that value changes.

Here is an example:

    $ cat junk.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>

    void error(const char *p)
    {
        fprintf(stderr, "Error in %s: %s\n", p, strerror(errno));
    }

    int main()
    {
        const char *fname = "/no/such/file";
        FILE *fp = fopen(fname, "r"); // sets errno
        if (!fp) {
            char *p = malloc(~(0UL)); // resets errno; but pretend we don't know this
            error("fopen");
        }
        return 0;
    }
    $ gcc -g junk.c && ./a.out
    Error in fopen: Cannot allocate memory

So, let's pretend we expected "Error in fopen: No such file or
directory" and got something else instead. Let's find out who
resets errno.

    $ gdb -q ./a.out
    Using host libthread_db library "/lib/tls/libthread_db.so.1".
    (gdb) b main
    Breakpoint 1 at 0x80484ef: file junk.c, line 12.
    (gdb) r

    Breakpoint 1, main () at junk.c:12
    12 const char *fname = "/no/such/file";
    (gdb) n
    13 FILE *fp = fopen(fname, "r"); // sets errno
    (gdb) n
    14 if (!fp) {
    (gdb) p errno
    Cannot access memory at address 0x8

That's not very good. We can't even look at the global "errno"
variable. This is because on Linux errno is actualy #define'd to
(*(__errno_location())).

Let's see what that function returns:

    (gdb) p/x __errno_location()
    $1 = 0xb7ff2440
    (gdb) x/x $1
    0xb7ff2440: 0x00000002

This is good: 2 == ENOFILE, which is what we expected.
Let's set a watchpoint and see what code modifies that value:

    (gdb) watch *(int *)$1
    Hardware watchpoint 2: *(int *) $1
    (gdb) c
    Hardware watchpoint 2: *(int *) $1

    Old value = 2
    New value = 12
    0x00bc1350 in _int_malloc () from /lib/tls/libc.so.6
    (gdb) bt
    #0 0x00bc1350 in _int_malloc () from /lib/tls/libc.so.6
    #1 0x00bc025d in malloc () from /lib/tls/libc.so.6
    #2 0x0804851c in main () at junk.c:15

So now we have the answer -- malloc() reset the errno.

Repeat this for your program, and the mistery should be solved.
Note that gdb will stop on the instruction that *follows* the one
that modified the value (and that instruction may be many lines
distant from the "culprit").

Cheers,

-- 
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.


Relevant Pages

  • Re: libpthread shared library version number
    ... everything -- world, ports, kernel. ... gdb showed me is: ... It seems that errno is being changed somewhere else?? ... UP kernel and see if that fixes the problem. ...
    (freebsd-current)
  • Re: libpthread shared library version number
    ... everything -- world, ports, kernel. ... gdb showed me is: ... It seems that errno is being changed somewhere else?? ... UP kernel and see if that fixes the problem. ...
    (freebsd-current)
  • Re: Header files with enums instead of defines?
    ... : M. Warner Losh wrote: ... :> In order to gain the benefits of the enums, errno would need to be an ... :> since you can't assign integers to errno values. ... but rather the type was used as a cast for gdb. ...
    (freebsd-arch)
  • Re: Header files with enums instead of defines?
    ... M. Warner Losh wrote: ... > In order to gain the benefits of the enums, errno would need to be an ... > since you can't assign integers to errno values. ... but rather the type was used as a cast for gdb. ...
    (freebsd-arch)
  • Re: errno/strerror() Observations
    ... something resets the errno ... ... SparcStation 5, I have access to x86/Linux so I'll try it out ... > In order to understand recursion you must first understand recursion. ...
    (comp.os.linux.development.apps)