darwin: fix uv_exepath(smallbuf) UV_EPERM error

Passing a buffer that was too small to hold the result made it fail
with UV_EPERM because the -1 status code from _NSGetExecutablePath()
was returned unmodified to the caller.

This commit rewrites uv_exepath() to:

1. Not allocate heap memory, and

2. Not clobber the result buffer on error, and

3. Handle _NSGetExecutablePath()'s and realpath()'s idiosyncracies, and

4. Store as much of the path in the output buffer as possible, don't
   fail with an error.  Makes it behave the same as other platforms.
   The result is always zero-terminated.

Fixes: https://github.com/libuv/libuv/issues/103
PR-URL: https://github.com/libuv/libuv/pull/104
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
Ben Noordhuis 2015-01-03 00:01:46 +01:00
parent afb319215d
commit 885b1ecda0
2 changed files with 28 additions and 15 deletions

View File

@ -65,28 +65,33 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
int uv_exepath(char* buffer, size_t* size) {
uint32_t usize;
int result;
char* path;
char* fullpath;
/* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
char abspath[PATH_MAX * 2 + 1];
char exepath[PATH_MAX + 1];
uint32_t exepath_size;
size_t abspath_size;
if (buffer == NULL || size == NULL || *size == 0)
return -EINVAL;
usize = *size;
result = _NSGetExecutablePath(buffer, &usize);
if (result) return result;
exepath_size = sizeof(exepath);
if (_NSGetExecutablePath(exepath, &exepath_size))
return -EIO;
path = malloc(2 * PATH_MAX);
fullpath = realpath(buffer, path);
if (fullpath == NULL) {
SAVE_ERRNO(free(path));
if (realpath(exepath, abspath) != abspath)
return -errno;
}
strncpy(buffer, fullpath, *size);
free(fullpath);
*size = strlen(buffer);
abspath_size = strlen(abspath);
if (abspath_size == 0)
return -EIO;
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
buffer[*size] = '\0';
return 0;
}

View File

@ -65,5 +65,13 @@ TEST_IMPL(get_currentexe) {
r = uv_exepath(buffer, &size);
ASSERT(r == UV_EINVAL);
memset(buffer, -1, sizeof(buffer));
size = 1;
r = uv_exepath(buffer, &size);
ASSERT(r == 0);
ASSERT(size == 0);
ASSERT(buffer[0] == '\0');
return 0;
}