Bug 168315 - [libc] [patch] add dirname_r(3); document ENOMEM conditions with basename(3) and dirname(3) functions
Summary: [libc] [patch] add dirname_r(3); document ENOMEM conditions with basename(3) ...
Status: Closed Overcome By Events
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: Unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: Enji Cooper
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-05-24 20:30 UTC by Enji Cooper
Modified: 2016-08-22 20:20 UTC (History)
3 users (show)

See Also:


Attachments
file.diff (3.42 KB, patch)
2012-05-24 20:30 UTC, Enji Cooper
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Enji Cooper freebsd_committer freebsd_triage 2012-05-24 20:30:06 UTC
Looking through the manpages today and inspecting the libc/gen/{base,dir}name.c, I noticed that there wasn't a dirname_r -- so I whipped one up quickly this morning and tested it out.

I also documented the undocumented errors that could occur if malloc(3) failed in basename(3) or dirname(3).

Fix: Patch attached with submission follows:
How-To-Repeat: $ cat ~/test_dirname.c
#include <sys/param.h>
#include <assert.h>
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct testcase {
        const char *input;
        const char *exp_res;
        int exp_errno;
};

struct testcase testcases[] = {
        { ".", ".", 0 },
        { "/", "/", 0 },
        { "", ".", 0 },
        { "a.b.c.d", ".", 0 },
        { "a/b/c/d", "a/b/c", 0 },
        { "a/b/c/d/", "a/b/c", 0 },
        { (const char*)NULL, ".", 0 },
        /* python -c 'print "/" + "a" * 1025 + "/b/"' */
        { "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/b/", NULL, ENAMETOOLONG },
};

int
main(int argc, char *argv[])
{
        char *buf, *res1, *res2;
        int failed, i;

        failed = 0;

        /* Slop */
        buf = malloc(5*MAXPATHLEN);
        assert(buf != NULL);

        for (i = 0; i < sizeof(testcases)/sizeof(testcases[0]); i++) {
                res1 = dirname(testcases[i].input);
                res2 = dirname_r(testcases[i].input, buf);
                if (testcases[i].exp_res == NULL) {
                        assert(res1 == res2);
                        if (res1 != NULL || errno != testcases[i].exp_errno) {
                                printf("FAIL: dirname(\"%s\") != NULL (was %s)\n", testcases[i].input, res1);
                                failed++;
                        } else if (errno != testcases[i].exp_errno) {
                                printf("FAIL: dirname(\"%s\") didn't set errno == %d (was %d)\n", testcases[i].input, testcases[i].exp_errno, errno);
                                failed++;
                        } else
                                printf("OK: dirname(\"%s\") == NULL and set errno == %d\n", testcases[i].input, testcases[i].exp_errno);
                } else {
                        assert(strcmp(res1, res2) == 0);
                        if (strcmp(res1, testcases[i].exp_res) != 0) {
                                printf("FAIL: dirname(\"%s\") != \"%s\" (was %s)\n", testcases[i].input, testcases[i].exp_res, res1);
                                failed++;
                        } else
                                printf("OK: dirname(\"%s\") == '%s'\n", testcases[i].input, testcases[i].exp_res);
                }
        }
        return (failed);
}
$ gcc -Wall -o ~/test_dirname ~/test_dirname.c
$ ~/test_dirname 
OK: dirname(".") == '.'
OK: dirname("/") == '/'
OK: dirname("") == '.'
OK: dirname("a.b.c.d") == '.'
OK: dirname("a/b/c/d") == 'a/b/c'
OK: dirname("a/b/c/d/") == 'a/b/c'
OK: dirname("(null)") == '.'
OK: dirname("/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/b/") == NULL and set errno == 63
$
Comment 1 Renato Botelho freebsd_committer freebsd_triage 2015-08-05 12:16:08 UTC
Garrett, do you still plan to get this committed? I was working on similar implementation and end up finding this PR.
Comment 2 Enji Cooper freebsd_committer freebsd_triage 2015-10-19 18:20:57 UTC
(In reply to Renato Botelho from comment #1)

I'll take this -- thanks :).
Comment 3 Ed Schouten freebsd_committer freebsd_triage 2016-08-22 20:20:37 UTC
Closing this bug, as dirname() in FreeBSD -HEAD has already been overhauled to be thread-safe. :-)