realpath(3) on a symlink that points to a non-existent path returns 
that path (but also sets errno), rather than returning NULL and 
setting errno.  This is inconsistent with at least Linux, FreeBSD, 
and macOS.

#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main()
{
        char resolved[1024];
        char *ret;

        unlink("/tmp/link");
        unlink("/tmp/nonexistent");
        symlink("/tmp/link", "/tmp/nonexistent");

        ret = realpath("/tmp/link", resolved);
        if (ret == NULL)
                printf("realpath failed: %s\n", strerror(errno));
        else
                printf("resolved realpath of %s (returned %s), errno is %d\n",
                    resolved, ret, errno);

        return (0);
}

Should print:
realpath failed: No such file or directory

But prints:
resolved realpath of /tmp/link (returned /tmp/link), errno is 2

This makes it fall through to the error case (in case any memory 
needs to be freed) and return NULL.


Index: lib/libc/stdlib/realpath.c
===================================================================
RCS file: /cvs/src/lib/libc/stdlib/realpath.c,v
retrieving revision 1.22
diff -u -p -u -p -r1.22 realpath.c
--- lib/libc/stdlib/realpath.c  24 Dec 2017 01:50:50 -0000      1.22
+++ lib/libc/stdlib/realpath.c  28 Jun 2018 02:24:37 -0000
@@ -163,10 +163,8 @@ realpath(const char *path, char *resolve
                                /* not a symlink, continue to next component */
                                continue;
                        case ENOENT:
-                               if (p == NULL) {
+                               if (p == NULL)
                                        errno = serrno;
-                                       return (resolved);
-                               }
                                /* FALLTHROUGH */
                        default:
                                goto err;

Reply via email to