Skip to content

Commit 177b35c

Browse files
authored
Avoid using GROW macro with hidden control flow (WebAssembly#751)
... and fix a memory leak in the case where it returns `NULL`.
1 parent ab1d04b commit 177b35c

1 file changed

Lines changed: 28 additions & 21 deletions

File tree

  • libc-bottom-half/cloudlibc/src/libc/dirent

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

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,21 @@ 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+
static struct dirent* grow(struct dirent **buffer, size_t *buffer_size, size_t target_size) {
36+
if (*buffer_size < target_size) {
37+
size_t new_size = *buffer_size;
38+
while (new_size < target_size)
39+
new_size *= 2;
40+
void *new_buffer = realloc(*buffer, new_size);
41+
if (new_buffer == NULL) {
42+
errno = ENOMEM;
43+
return NULL;
44+
}
45+
*buffer = new_buffer;
46+
*buffer_size = new_size;
47+
}
48+
return *buffer;
49+
}
5050

5151
#if defined(__wasip1__)
5252
struct dirent *readdir(DIR *dirp) {
@@ -73,7 +73,8 @@ struct dirent *readdir(DIR *dirp) {
7373
// the entry another time. Ensure that the read buffer is large
7474
// enough to fit at least this single entry.
7575
if (buffer_left < entry_size) {
76-
GROW(dirp->buffer, dirp->buffer_size, entry_size);
76+
if (grow((struct dirent**) &dirp->buffer, &dirp->buffer_size, entry_size) == NULL)
77+
return NULL;
7778
goto read_entries;
7879
}
7980

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

8788
// Return the next directory entry. Ensure that the dirent is large
8889
// enough to fit the filename.
89-
GROW(dirp->dirent, dirp->dirent_size,
90-
offsetof(struct dirent, d_name) + entry.d_namlen + 1);
90+
if (grow(&dirp->dirent, &dirp->dirent_size,
91+
offsetof(struct dirent, d_name) + entry.d_namlen + 1) == NULL)
92+
return NULL;
9193
struct dirent *dirent = dirp->dirent;
9294
dirent->d_type = entry.d_type;
9395
memcpy(dirent->d_name, name, entry.d_namlen);
@@ -172,7 +174,8 @@ static struct dirent *readdir_next(DIR *dirp) {
172174
// hash of the directory itself.
173175
if (dirp->offset == 0) {
174176
dirp->offset += 1;
175-
GROW(dirp->dirent, dirp->dirent_size, offsetof(struct dirent, d_name) + 2);
177+
if (grow(&dirp->dirent, &dirp->dirent_size, offsetof(struct dirent, d_name) + 2) == NULL)
178+
return NULL;
176179
bool ok = filesystem_method_descriptor_metadata_hash(dir_handle,
177180
&metadata,
178181
&error_code);
@@ -191,7 +194,8 @@ static struct dirent *readdir_next(DIR *dirp) {
191194
// avoid opening the parent directory here.
192195
if (dirp->offset == 1) {
193196
dirp->offset += 1;
194-
GROW(dirp->dirent, dirp->dirent_size, offsetof(struct dirent, d_name) + 3);
197+
if (grow(&dirp->dirent, &dirp->dirent_size, offsetof(struct dirent, d_name) + 3) == NULL)
198+
return NULL;
195199
dirp->dirent->d_ino = 0;
196200
dirp->dirent->d_type = DT_DIR;
197201
dirp->dirent->d_name[0] = '.';
@@ -218,7 +222,10 @@ static struct dirent *readdir_next(DIR *dirp) {
218222

219223
// Ensure that the dirent is large enough to fit the filename
220224
size_t the_size = offsetof(struct dirent, d_name);
221-
GROW(dirp->dirent, dirp->dirent_size, the_size + dir_entry.name.len + 1);
225+
if (grow(&dirp->dirent, &dirp->dirent_size, the_size + dir_entry.name.len + 1) == NULL) {
226+
wasip2_string_free(&dir_entry.name);
227+
return NULL;
228+
}
222229

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

0 commit comments

Comments
 (0)