FileLister: ensure enough space for resulting dirent (#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.
This commit is contained in:
parent
2624d791e6
commit
0a50d8e8f4
|
@ -189,12 +189,26 @@ static void addFiles2(std::map<std::string, std::size_t> &files,
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dirent entry;
|
|
||||||
dirent * dir_result;
|
dirent * dir_result;
|
||||||
|
// make sure we reserve enough space for the readdir_r() buffer;
|
||||||
|
// according to POSIX:
|
||||||
|
// The storage pointed to by entry shall be large enough for a
|
||||||
|
// dirent with an array of char d_name members containing at
|
||||||
|
// least {NAME_MAX}+1 elements.
|
||||||
|
// on some platforms, d_name is not a static sized-array but
|
||||||
|
// a pointer to space usually reserved right after the dirent
|
||||||
|
// struct; the union here allows to reserve the space and to
|
||||||
|
// provide a pointer to the right type that can be passed where
|
||||||
|
// needed without casts
|
||||||
|
union {
|
||||||
|
dirent entry;
|
||||||
|
char buf[sizeof(*dir_result) + (sizeof(dir_result->d_name) > 1 ? 0 : NAME_MAX + 1)];
|
||||||
|
} dir_result_buffer;
|
||||||
|
UNUSED(dir_result_buffer.buf); // do not trigger cppcheck itself on the "unused buf"
|
||||||
std::string new_path;
|
std::string new_path;
|
||||||
new_path.reserve(path.length() + 100);// prealloc some memory to avoid constant new/deletes in loop
|
new_path.reserve(path.length() + 100);// prealloc some memory to avoid constant new/deletes in loop
|
||||||
|
|
||||||
while ((readdir_r(dir, &entry, &dir_result) == 0) && (dir_result != nullptr)) {
|
while ((readdir_r(dir, &dir_result_buffer.entry, &dir_result) == 0) && (dir_result != nullptr)) {
|
||||||
|
|
||||||
if ((std::strcmp(dir_result->d_name, ".") == 0) ||
|
if ((std::strcmp(dir_result->d_name, ".") == 0) ||
|
||||||
(std::strcmp(dir_result->d_name, "..") == 0))
|
(std::strcmp(dir_result->d_name, "..") == 0))
|
||||||
|
|
Loading…
Reference in New Issue