Skip to content

Commit 2c1c280

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

5 files changed

Lines changed: 215 additions & 198 deletions

File tree

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

Lines changed: 8 additions & 7 deletions
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

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,54 +8,63 @@
88
#include <wasi/libc-find-relpath.h>
99
#include <wasi/libc.h>
1010

11-
char *__wasilibc_cwd = "/";
11+
extern char *__wasilibc_cwd;
1212
static int __wasilibc_cwd_mallocd = 0;
1313

1414
int chdir(const char *path)
1515
{
16-
// Find a preopen'd directory as well as a relative path we're anchored
17-
// from which we're changing directories to.
18-
char *relative;
19-
const char *abs;
20-
int parent_fd = __wasilibc_find_relpath(path, &abs, &relative);
21-
if (parent_fd == -1) {
22-
errno = ENOENT;
23-
return -1;
24-
}
16+
static char *relative_buf = NULL;
17+
static size_t relative_buf_len = 0;
2518

26-
// Make sure that this directory we're accessing is indeed a directory.
27-
struct stat dirinfo;
28-
int ret = fstatat(parent_fd, relative, &dirinfo, 0);
29-
if (ret == -1) {
30-
free(relative);
31-
return -1;
32-
}
33-
if (!S_ISDIR(dirinfo.st_mode)) {
34-
free(relative);
35-
errno = ENOTDIR;
36-
return -1;
37-
}
19+
// Find a preopen'd directory as well as a relative path we're anchored
20+
// from which we're changing directories to.
21+
const char *abs;
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;
36+
}
3837

39-
// Copy over our new absolute path into `__wasilibc_cwd`. Only copy over
40-
// the relative portion of the path if it's not equal to `.`
41-
size_t len = strlen(abs);
42-
int copy_relative = strcmp(relative, ".") != 0;
43-
char *new_cwd = malloc(len + (copy_relative ? strlen(relative) : 0));
44-
if (new_cwd == NULL) {
45-
errno = ENOMEM;
46-
return -1;
47-
}
48-
strcpy(new_cwd, abs);
49-
if (copy_relative)
50-
strcpy(new_cwd + strlen(abs), relative);
51-
free(relative);
38+
// Make sure that this directory we're accessing is indeed a directory.
39+
struct stat dirinfo;
40+
int ret = fstatat(parent_fd, relative_buf, &dirinfo, 0);
41+
if (ret == -1) {
42+
return -1;
43+
}
44+
if (!S_ISDIR(dirinfo.st_mode)) {
45+
errno = ENOTDIR;
46+
return -1;
47+
}
5248

53-
// And set our new malloc'd buffer into the global cwd, freeing the
54-
// previous one if necessary.
55-
char *prev_cwd = __wasilibc_cwd;
56-
__wasilibc_cwd = new_cwd;
57-
if (__wasilibc_cwd_mallocd)
58-
free(prev_cwd);
59-
__wasilibc_cwd_mallocd = 1;
60-
return 0;
49+
// Copy over our new absolute path into `__wasilibc_cwd`. Only copy over
50+
// the relative portion of the path if it's not equal to `.`
51+
size_t len = strlen(abs);
52+
int copy_relative = strcmp(relative_buf, ".") != 0;
53+
char *new_cwd = malloc(len + (copy_relative ? strlen(relative_buf) : 0));
54+
if (new_cwd == NULL) {
55+
errno = ENOMEM;
56+
return -1;
57+
}
58+
strcpy(new_cwd, abs);
59+
if (copy_relative)
60+
strcpy(new_cwd + strlen(abs), relative_buf);
61+
62+
// And set our new malloc'd buffer into the global cwd, freeing the
63+
// previous one if necessary.
64+
char *prev_cwd = __wasilibc_cwd;
65+
__wasilibc_cwd = new_cwd;
66+
if (__wasilibc_cwd_mallocd)
67+
free(prev_cwd);
68+
__wasilibc_cwd_mallocd = 1;
69+
return 0;
6170
}

libc-bottom-half/sources/getcwd.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@
22
#include <errno.h>
33
#include <string.h>
44

5-
extern char *__wasilibc_cwd;
5+
char *__wasilibc_cwd = "/";
66

77
char *getcwd(char *buf, size_t size)
88
{
9-
if (!buf) {
10-
buf = strdup(__wasilibc_cwd);
119
if (!buf) {
12-
errno = ENOMEM;
13-
return -1;
10+
buf = strdup(__wasilibc_cwd);
11+
if (!buf) {
12+
errno = ENOMEM;
13+
return NULL;
14+
}
15+
} else {
16+
size_t len = strlen(__wasilibc_cwd);
17+
if (size < strlen(__wasilibc_cwd) + 1) {
18+
errno = ERANGE;
19+
return NULL;
20+
}
21+
strcpy(buf, __wasilibc_cwd);
1422
}
15-
} else {
16-
size_t len = strlen(__wasilibc_cwd);
17-
if (size < strlen(__wasilibc_cwd) + 1) {
18-
errno = ERANGE;
19-
return 0;
20-
}
21-
strcpy(buf, __wasilibc_cwd);
22-
}
23-
return buf;
23+
return buf;
2424
}
2525

0 commit comments

Comments
 (0)