Skip to content

Commit 0a50d8e

Browse files
authored
FileLister: ensure enough space for resulting dirent (cppcheck-opensource#2850)
On some platforms, the 'd_name' field of struct dirent is not a static fixed-sized array but a "flexarray" (i.e. a single character); in this situation, 'd_name' points to a buffer allocated somewhere, usually at the end of the buffer used for dirent (which is then allocated in a bigger memory). Because of this, creating a struct dirent on stack as buffer for readdir_r is not enough to store all the memory needed for a dirent on those platforms. As result, create an helper union with all the needed space, calculated statically at build time. NAME_MAX+1 is still not a perfect option, but it will do the job in the vast majority of cases.
1 parent 2624d79 commit 0a50d8e

1 file changed

Lines changed: 16 additions & 2 deletions

File tree

cli/filelister.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,26 @@ static void addFiles2(std::map<std::string, std::size_t> &files,
189189
if (!dir)
190190
return;
191191

192-
dirent entry;
193192
dirent * dir_result;
193+
// make sure we reserve enough space for the readdir_r() buffer;
194+
// according to POSIX:
195+
// The storage pointed to by entry shall be large enough for a
196+
// dirent with an array of char d_name members containing at
197+
// least {NAME_MAX}+1 elements.
198+
// on some platforms, d_name is not a static sized-array but
199+
// a pointer to space usually reserved right after the dirent
200+
// struct; the union here allows to reserve the space and to
201+
// provide a pointer to the right type that can be passed where
202+
// needed without casts
203+
union {
204+
dirent entry;
205+
char buf[sizeof(*dir_result) + (sizeof(dir_result->d_name) > 1 ? 0 : NAME_MAX + 1)];
206+
} dir_result_buffer;
207+
UNUSED(dir_result_buffer.buf); // do not trigger cppcheck itself on the "unused buf"
194208
std::string new_path;
195209
new_path.reserve(path.length() + 100);// prealloc some memory to avoid constant new/deletes in loop
196210

197-
while ((readdir_r(dir, &entry, &dir_result) == 0) && (dir_result != nullptr)) {
211+
while ((readdir_r(dir, &dir_result_buffer.entry, &dir_result) == 0) && (dir_result != nullptr)) {
198212

199213
if ((std::strcmp(dir_result->d_name, ".") == 0) ||
200214
(std::strcmp(dir_result->d_name, "..") == 0))

0 commit comments

Comments
 (0)