Skip to content

Commit 73dc73c

Browse files
committed
Avoid using GROW macro with hidden control flow
... and fix a memory leak in the case where it returns `NULL`.
1 parent 6016e71 commit 73dc73c

File tree

1 file changed

+33
-21
lines changed
  • libc-bottom-half/cloudlibc/src/libc/dirent

1 file changed

+33
-21
lines changed

libc-bottom-half/cloudlibc/src/libc/dirent/readdir.c

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,26 @@ static_assert(DT_UNKNOWN == __WASI_FILETYPE_UNKNOWN, "Value mismatch");
3232
#endif
3333

3434
// Grows a buffer to be large enough to hold a certain amount of data.
35-
#define GROW(buffer, buffer_size, target_size) \
36-
do { \
37-
if ((buffer_size) < (target_size)) { \
38-
size_t new_size = (buffer_size); \
39-
while (new_size < (target_size)) \
40-
new_size *= 2; \
41-
void *new_buffer = realloc(buffer, new_size); \
42-
if (new_buffer == NULL) { \
43-
errno = ENOMEM; \
44-
return NULL; \
45-
} \
46-
(buffer) = new_buffer; \
47-
(buffer_size) = new_size; \
48-
} \
49-
} while (0)
35+
#ifdef __wasip1__
36+
typedef void* buffer_t;
37+
#else
38+
typedef struct dirent* buffer_t;
39+
#endif
40+
static buffer_t grow(buffer_t *buffer, size_t *buffer_size, size_t target_size) {
41+
if (*buffer_size < target_size) {
42+
size_t new_size = *buffer_size;
43+
while (new_size < target_size)
44+
new_size *= 2;
45+
void *new_buffer = realloc(*buffer, new_size);
46+
if (new_buffer == NULL) {
47+
errno = ENOMEM;
48+
return NULL;
49+
}
50+
*buffer = new_buffer;
51+
*buffer_size = new_size;
52+
}
53+
return *buffer;
54+
}
5055

5156
#if defined(__wasip1__)
5257
struct dirent *readdir(DIR *dirp) {
@@ -73,7 +78,8 @@ struct dirent *readdir(DIR *dirp) {
7378
// the entry another time. Ensure that the read buffer is large
7479
// enough to fit at least this single entry.
7580
if (buffer_left < entry_size) {
76-
GROW(dirp->buffer, dirp->buffer_size, entry_size);
81+
if (grow(&dirp->buffer, &dirp->buffer_size, entry_size) == NULL)
82+
return NULL;
7783
goto read_entries;
7884
}
7985

@@ -86,8 +92,9 @@ struct dirent *readdir(DIR *dirp) {
8692

8793
// Return the next directory entry. Ensure that the dirent is large
8894
// enough to fit the filename.
89-
GROW(dirp->dirent, dirp->dirent_size,
90-
offsetof(struct dirent, d_name) + entry.d_namlen + 1);
95+
if (grow(&dirp->dirent, &dirp->dirent_size,
96+
offsetof(struct dirent, d_name) + entry.d_namlen + 1))
97+
return NULL;
9198
struct dirent *dirent = dirp->dirent;
9299
dirent->d_type = entry.d_type;
93100
memcpy(dirent->d_name, name, entry.d_namlen);
@@ -172,7 +179,8 @@ static struct dirent *readdir_next(DIR *dirp) {
172179
// hash of the directory itself.
173180
if (dirp->offset == 0) {
174181
dirp->offset += 1;
175-
GROW(dirp->dirent, dirp->dirent_size, offsetof(struct dirent, d_name) + 2);
182+
if (grow(&dirp->dirent, &dirp->dirent_size, offsetof(struct dirent, d_name) + 2) == NULL)
183+
return NULL;
176184
bool ok = filesystem_method_descriptor_metadata_hash(dir_handle,
177185
&metadata,
178186
&error_code);
@@ -191,7 +199,8 @@ static struct dirent *readdir_next(DIR *dirp) {
191199
// avoid opening the parent directory here.
192200
if (dirp->offset == 1) {
193201
dirp->offset += 1;
194-
GROW(dirp->dirent, dirp->dirent_size, offsetof(struct dirent, d_name) + 3);
202+
if (grow(&dirp->dirent, &dirp->dirent_size, offsetof(struct dirent, d_name) + 3) == NULL)
203+
return NULL;
195204
dirp->dirent->d_ino = 0;
196205
dirp->dirent->d_type = DT_DIR;
197206
dirp->dirent->d_name[0] = '.';
@@ -218,7 +227,10 @@ static struct dirent *readdir_next(DIR *dirp) {
218227

219228
// Ensure that the dirent is large enough to fit the filename
220229
size_t the_size = offsetof(struct dirent, d_name);
221-
GROW(dirp->dirent, dirp->dirent_size, the_size + dir_entry.name.len + 1);
230+
if (grow(&dirp->dirent, &dirp->dirent_size, the_size + dir_entry.name.len + 1) == NULL) {
231+
wasip2_string_free(&dir_entry.name);
232+
return NULL;
233+
}
222234

223235
// Fill out `d_type` and `d_name`
224236
dirp->dirent->d_type = dir_entry_type_to_d_type(dir_entry.type);

0 commit comments

Comments
 (0)