Skip to content

Commit d1e85ab

Browse files
committed
Amortize mallocs made in syscalls
1 parent 874df5b commit d1e85ab

File tree

5 files changed

+171
-153
lines changed

5 files changed

+171
-153
lines changed

libc-bottom-half/headers/public/wasi/libc-find-relpath.h

+8-7
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,19 @@ extern "C" {
1010
* map. If a suitable entry is found, then the file descriptor for that entry
1111
* is returned. Additionally the absolute path of the directory's file
1212
* descriptor is returned in `abs_prefix` and the relative portion that needs
13-
* to be opened is stored in `relative_path`.
13+
* to be opened is stored in `relative_path`. The size of the `relative_path`
14+
* buffer is provided in the `relative_path_len` argument.
1415
*
15-
* Returns -1 if no directories were suitable or if an allocation error
16-
* happens.
16+
* Returns -1 on failure. Errno is set to either:
1717
*
18-
* On success the `relative_path` points to a malloc'd string, so you'll
19-
* need to call `free` on it. The `abs_prefix` return does not need to be
20-
* free'd.
18+
* * ENOMEM - failed to allocate memory for internal routines.
19+
* * ENOENT - the `path` could not be found relative to any preopened dir.
20+
* * ERANGE - the `relative_path` buffer is too small to hold the relative path.
2121
*/
2222
int __wasilibc_find_relpath(const char *path,
2323
const char **__restrict__ abs_prefix,
24-
char **__restrict__ relative_path);
24+
char *relative_path,
25+
size_t relative_path_len);
2526

2627
#ifdef __cplusplus
2728
}

libc-bottom-half/sources/chdir.c

+21-12
Original file line numberDiff line numberDiff line change
@@ -13,42 +13,51 @@ static int __wasilibc_cwd_mallocd = 0;
1313

1414
int chdir(const char *path)
1515
{
16+
static char *relative_buf = NULL;
17+
static size_t relative_buf_len = 0;
18+
1619
// Find a preopen'd directory as well as a relative path we're anchored
1720
// from which we're changing directories to.
18-
char *relative;
1921
const char *abs;
20-
int parent_fd = __wasilibc_find_relpath(path, &abs, &relative);
21-
if (parent_fd == -1) {
22-
errno = ENOENT;
23-
return -1;
22+
int parent_fd;
23+
while (1) {
24+
parent_fd = __wasilibc_find_relpath(path, &abs, relative_buf, relative_buf_len);
25+
if (parent_fd != -1)
26+
break;
27+
if (errno != ERANGE)
28+
return -1;
29+
size_t new_len = relative_buf_len == 0 ? 16 : 2 * relative_buf_len;
30+
relative_buf = realloc(relative_buf, new_len);
31+
if (relative_buf == NULL) {
32+
errno = ENOMEM;
33+
return -1;
34+
}
35+
relative_buf_len = new_len;
2436
}
2537

2638
// Make sure that this directory we're accessing is indeed a directory.
2739
struct stat dirinfo;
28-
int ret = fstatat(parent_fd, relative, &dirinfo, 0);
40+
int ret = fstatat(parent_fd, relative_buf, &dirinfo, 0);
2941
if (ret == -1) {
30-
free(relative);
3142
return -1;
3243
}
3344
if (!S_ISDIR(dirinfo.st_mode)) {
34-
free(relative);
3545
errno = ENOTDIR;
3646
return -1;
3747
}
3848

3949
// Copy over our new absolute path into `__wasilibc_cwd`. Only copy over
4050
// the relative portion of the path if it's not equal to `.`
4151
size_t len = strlen(abs);
42-
int copy_relative = strcmp(relative, ".") != 0;
43-
char *new_cwd = malloc(len + (copy_relative ? strlen(relative) : 0));
52+
int copy_relative = strcmp(relative_buf, ".") != 0;
53+
char *new_cwd = malloc(len + (copy_relative ? strlen(relative_buf) : 0));
4454
if (new_cwd == NULL) {
4555
errno = ENOMEM;
4656
return -1;
4757
}
4858
strcpy(new_cwd, abs);
4959
if (copy_relative)
50-
strcpy(new_cwd + strlen(abs), relative);
51-
free(relative);
60+
strcpy(new_cwd + strlen(abs), relative_buf);
5261

5362
// And set our new malloc'd buffer into the global cwd, freeing the
5463
// previous one if necessary.

libc-bottom-half/sources/getcwd.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ char *getcwd(char *buf, size_t size)
1010
buf = strdup(__wasilibc_cwd);
1111
if (!buf) {
1212
errno = ENOMEM;
13-
return -1;
13+
return NULL;
1414
}
1515
} else {
1616
size_t len = strlen(__wasilibc_cwd);
1717
if (size < strlen(__wasilibc_cwd) + 1) {
1818
errno = ERANGE;
19-
return 0;
19+
return NULL;
2020
}
2121
strcpy(buf, __wasilibc_cwd);
2222
}

0 commit comments

Comments
 (0)