10000 struct dirent is variable length in the original POSIX specification … · python/cpython@93e1687 · GitHub
[go: up one dir, main page]

Skip to content

Commit 93e1687

Browse files
committed
struct dirent is variable length in the original POSIX specification (the final
filename field being an unsized array) and in actual practice on the WASI platform. Thus just copying one into a stack-allocated structure is not good enough. The obvious way to address this is to allocate memory on the heap and return that. However, it seems wasteful to dynamically allocate a temporary chunk of data just to copy some data in and then out again. Instead, if the name field is potentially not long enough, allocate some extra space *on the stack* following the structure such that it must be sufficient to hold the the full record length (and copy all of that, not just the potentially smaller fixed structure size).
1 parent 6b3b46d commit 93e1687

File tree

1 file changed

+16
-2
lines changed

1 file changed

+16
-2
lines changed

Modules/posixmodule.c

Lines changed: 16 additions & 2 deletions
8000
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,9 @@
204204
# include <sanitizer/msan_interface.h> // __msan_unpoison()
205205
#endif
206206

207+
#ifdef HAVE_ALLOCA_H
208+
#include <alloca.h>
209+
#endif
207210

208211
// --- More complex system includes -----------------------------------------
209212

@@ -16305,7 +16308,7 @@ ScandirIterator_nextdirentry(ScandirIterator *iterator, struct dirent *direntp)
1630516308
}
1630616309
/* We need to make a copy of the result before releasing the lock */
1630716310
if (result)
16308-
memcpy(direntp, result, sizeof(struct dirent));
16311+
memcpy(direntp, result, result->d_reclen);
1630916312
PyMutex_Unlock(&iterator->mutex);
1631016313

1631116314
/* Error or no more files */
@@ -16320,12 +16323,22 @@ ScandirIterator_nextdirentry(ScandirIterator *iterator, struct dirent *direntp)
1632016323
static PyObject *
1632116324
ScandirIterator_iternext(PyObject *op)
1632216325
{
16326+
ScandirIterator *iterator = ScandirIterator_CAST(op);
1632316327
#ifdef MS_WINDOWS
1632416328
WIN32_FIND_DATAW dirent;
1632516329
#else
16330+
/*
16331+
* This may be a variable length structure, with the final "d_name" field
16332+
* possibly being a flexible array member. In that case allocate enough
16333+
* extra space on the stack, immediately following the structure,
16334+
* sufficient to handle the longest possible filename. */
1632616335
struct dirent dirent;
16336+
if (sizeof(dirent.d_name) < (NAME_MAX + 1)
16337+
&& !alloca(NAME_MAX + 1 - sizeof(dirent.d_name))) {
16338+
PyErr_NoMemory();
16339+
goto error;
16340+
}
1632716341
#endif
16328-
ScandirIterator *iterator = ScandirIterator_CAST(op);
1632916342

1633016343
while ((ScandirIterator_nextdirentry(iterator, &dirent))) {
1633116344

@@ -16341,6 +16354,7 @@ ScandirIterator_iternext(PyObject *op)
1634116354
}
1634216355

1634316356
/* Already closed, error, or no more files */
16357+
error:
1634416358
ScandirIterator_closedir(iterator);
1634516359
return NULL;
1634616360
}

0 commit comments

Comments
 (0)
0