On Linux, getcwd(2) can succeed without returning an absolute path. I just documented that in a man-pages patch I sent to the man-pages ML and maintainer, a copy is at <http://var.thejh.net/0001-getcwd.3-behavior-for-unreachable-cwd.patch>. This behavior causes realpath to behave inconsistently when dealing with unreachable paths: $ cat getcwd.c #define _GNU_SOURCE #include <sched.h> #include <unistd.h> #include <stdio.h> #include <limits.h> #include <stdlib.h> int main(void) { unshare(CLONE_NEWUSER | CLONE_NEWNS); chdir("/usr"); chroot("bin"); printf("current directory: \"%s\"\n", get_current_dir_name()); char *real = realpath(".", NULL); printf("realpath of .: \"%s\"\n", real ? real : "{none}"); real = realpath("../home/jann/.ssh", NULL); printf("realpath of path: \"%s\"\n", real ? real : "{none}"); return 0; } $ gcc -o getcwd getcwd.c $ ./getcwd current directory: "(unreachable)/usr" realpath of .: "(unreachable)/usr" realpath of path: "{none}" $ strace ./getcwd [...] unshare(CLONE_NEWNS|CLONE_NEWUSER) = 0 chdir("/usr") = 0 chroot("bin") = 0 stat(".", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 stat("/media/wdgreen/home/jann/tmp", 0x7fff685a5af0) = -1 ENOENT (No such file or directory) brk(0) = 0x7c6000 brk(0x7e8000) = 0x7e8000 getcwd("(unreachable)/usr", 4096) = 18 brk(0x7e7000) = 0x7e7000 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f58a5941000 write(1, "current directory: \"(unreachable"..., 39current directory: "(unreachable)/usr" ) = 39 getcwd("(unreachable)/usr", 4096) = 18 write(1, "realpath of .: \"(unreachable)/us"..., 35realpath of .: "(unreachable)/usr" ) = 35 getcwd("(unreachable)/usr", 4096) = 18 lstat("(unreachable)/home", 0x7fff685a5ac0) = -1 ENOENT (No such file or directory) write(1, "realpath of path: \"{none}\"\n", 27realpath of path: "{none}" ) = 27 exit_group(0) = ? +++ exited with 0 +++ As you can see, realpath attempts to lstat() the unreachable path returned by getcwd() in the last invocation. I think the sanest option to deal with this would be to let realpath() error out if getcwd() returns a path that does not start with a slash, but I'm not sure about which errno value to use. Maybe ENOENT, with the reasoning "if it's not under the root, it doesn't really exist to us"?
Fixed by https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=52a713fdd0a30e1bd79818e2e3c4ab44ddca1a94