Skip to content

Commit 5ab6f1c

Browse files
committed
Make readdir reentrant
Remove the static allocation for the dirent, and allocate it from the heap during opendir(). Removing the static data can reduce RAM usage on some toolchains when directories are not being used. The static allocation sometimes is combined with the file handle array and can't be dropped by the linker. Original readdir() was not thread-safe at all. This was in violation of POSIX which states the result of readdir "is not overwritten by another call to readdir() on a different directory stream." POSIX also defines readdir_r() as separate totally reentrant form where the caller allocates the dirent, but this is generally deprecated as it opens the door for an inadequate allocation causing a stack smash. Full reentrancy is not typically necessary - having readdir()'s buffer data be per-DIR is generally sufficient.
1 parent 54f0f56 commit 5ab6f1c

File tree

2 files changed

+22
-13
lines changed

2 files changed

+22
-13
lines changed

platform/include/platform/mbed_retarget.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,8 @@ FileHandle *mbed_override_console(int fd);
184184
*/
185185
FileHandle *mbed_file_handle(int fd);
186186
}
187-
188-
typedef mbed::DirHandle DIR;
189-
#else
190-
typedef struct Dir DIR;
191187
#endif
188+
typedef struct DIR_impl DIR;
192189
#endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY
193190

194191
/* The intent of this section is to unify the errno error values to match

platform/source/mbed_retarget.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@
4646

4747
static SingletonPtr<PlatformMutex> _mutex;
4848

49+
/* DIR is typedeffed to struct DIR_impl in header */
50+
struct DIR_impl {
51+
mbed::DirHandle *handle;
52+
struct dirent entry;
53+
};
54+
4955
#if defined(__ARMCC_VERSION)
5056
# include <arm_compat.h>
5157
# include <rt_sys.h>
@@ -1297,9 +1303,15 @@ extern "C" DIR *opendir(const char *path)
12971303
return NULL;
12981304
}
12991305

1300-
DirHandle *dir;
1301-
int err = fs->open(&dir, fp.fileName());
1306+
DIR *dir = new (std::nothrow) DIR;
1307+
if (!dir) {
1308+
errno = ENOMEM;
1309+
return NULL;
1310+
}
1311+
1312+
int err = fs->open(&dir->handle, fp.fileName());
13021313
if (err < 0) {
1314+
delete dir;
13031315
errno = -err;
13041316
return NULL;
13051317
}
@@ -1309,21 +1321,21 @@ extern "C" DIR *opendir(const char *path)
13091321

13101322
extern "C" struct dirent *readdir(DIR *dir)
13111323
{
1312-
static struct dirent ent;
1313-
int err = dir->read(&ent);
1324+
int err = dir->handle->read(&dir->entry);
13141325
if (err < 1) {
13151326
if (err < 0) {
13161327
errno = -err;
13171328
}
13181329
return NULL;
13191330
}
13201331

1321-
return &ent;
1332+
return &dir->entry;
13221333
}
13231334

13241335
extern "C" int closedir(DIR *dir)
13251336
{
1326-
int err = dir->close();
1337+
int err = dir->handle->close();
1338+
delete dir;
13271339
if (err < 0) {
13281340
errno = -err;
13291341
return -1;
@@ -1334,17 +1346,17 @@ extern "C" int closedir(DIR *dir)
13341346

13351347
extern "C" void rewinddir(DIR *dir)
13361348
{
1337-
dir->rewind();
1349+
dir->handle->rewind();
13381350
}
13391351

13401352
extern "C" off_t telldir(DIR *dir)
13411353
{
1342-
return dir->tell();
1354+
return dir->handle->tell();
13431355
}
13441356

13451357
extern "C" void seekdir(DIR *dir, off_t off)
13461358
{
1347-
dir->seek(off);
1359+
dir->handle->seek(off);
13481360
}
13491361

13501362
extern "C" int mkdir(const char *path, mode_t mode)

0 commit comments

Comments
 (0)