Skip to content

Commit fb7cbdf

Browse files
kjbraceyHasnain Virk
authored andcommitted
Tighten mbed_retarget.cpp error handling
* Don't set errno when calls are successful (will slightly alleviate the problem of errno not being thread-safe yet). * Transfer errors returned from size() and seek() into errno. * Fix isatty() - could never return 1 from a FileHandle. * Use more appropriate errors than EBADF in some places (eg ENOENT for non-existant path).
1 parent 533910c commit fb7cbdf

File tree

2 files changed

+139
-86
lines changed

2 files changed

+139
-86
lines changed

platform/mbed_retarget.cpp

Lines changed: 122 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#endif
3131
#include <stdlib.h>
3232
#include <string.h>
33+
#include <limits.h>
3334
#if DEVICE_STDIO_MESSAGES
3435
#include <stdio.h>
3536
#endif
@@ -120,6 +121,17 @@ static void init_serial() {
120121
#endif
121122
}
122123

124+
/**
125+
* Sets errno when file opening fails.
126+
* Wipes out the filehandle too.
127+
*/
128+
static int handle_open_errors(int error, unsigned filehandle_idx) {
129+
errno = -error;
130+
// Free file handle
131+
filehandles[filehandle_idx] = NULL;
132+
return -1;
133+
}
134+
123135
#if MBED_CONF_FILESYSTEM_PRESENT
124136
static inline int openmode_to_posix(int openmode) {
125137
int posix = openmode;
@@ -189,7 +201,7 @@ class ManagedDir : public Dir {
189201
* @return
190202
* On success, a valid FILEHANDLE is returned.
191203
* On failure, -1 is returned and errno is set to an appropriate value e.g.
192-
* EBADF a bad file descriptor was found (default errno setting)
204+
* ENOENT file not found (default errno setting)
193205
* EMFILE the maximum number of open files was exceeded.
194206
*
195207
* */
@@ -219,9 +231,6 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
219231
}
220232
#endif
221233

222-
/* if something goes wrong and errno is not explicly set, errno will be set to EBADF */
223-
errno = EBADF;
224-
225234
// find the first empty slot in filehandles
226235
filehandle_mutex->lock();
227236
unsigned int fh_i;
@@ -253,41 +262,30 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
253262
if (!path.exists()) {
254263
/* The first part of the filename (between first 2 '/') is not a
255264
* registered mount point in the namespace.
256-
* Free file handle.
257265
*/
258-
filehandles[fh_i] = NULL;
259-
errno = ENOENT;
260-
return -1;
261-
} else if (path.isFile()) {
266+
return handle_open_errors(-ENOENT, fh_i);
267+
}
268+
269+
if (path.isFile()) {
262270
res = path.file();
263271
#if MBED_CONF_FILESYSTEM_PRESENT
264272
} else {
265273
FileSystem *fs = path.fileSystem();
266274
if (fs == NULL) {
267-
/* The filesystem instance managing the namespace under the mount point
268-
* has not been found. Free file handle */
269-
errno = ENOENT;
270-
filehandles[fh_i] = NULL;
271-
return -1;
275+
return handle_open_errors(-ENOENT, fh_i);
272276
}
273277
int posix_mode = openmode_to_posix(openmode);
274278
File *file = new ManagedFile;
275279
int err = file->open(fs, path.fileName(), posix_mode);
276280
if (err < 0) {
277-
errno = -err;
278281
delete file;
279-
} else {
280-
res = file;
282+
return handle_open_errors(err, fh_i);
281283
}
284+
res = file;
282285
#endif
283286
}
284287
}
285288

286-
if (res == NULL) {
287-
// Free file handle
288-
filehandles[fh_i] = NULL;
289-
return -1;
290-
}
291289
filehandles[fh_i] = res;
292290

293291
return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err
@@ -296,10 +294,12 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
296294
extern "C" int PREFIX(_close)(FILEHANDLE fh) {
297295
if (fh < 3) return 0;
298296

299-
errno = EBADF;
300297
FileHandle* fhc = filehandles[fh-3];
301298
filehandles[fh-3] = NULL;
302-
if (fhc == NULL) return -1;
299+
if (fhc == NULL) {
300+
errno = EBADF;
301+
return -1;
302+
}
303303

304304
int err = fhc->close();
305305
if (err < 0) {
@@ -317,7 +317,6 @@ extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsign
317317
#endif
318318
int n; // n is the number of bytes written
319319

320-
errno = EBADF;
321320
if (fh < 3) {
322321
#if DEVICE_SERIAL
323322
if (!stdio_uart_inited) init_serial();
@@ -338,7 +337,10 @@ extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsign
338337
n = length;
339338
} else {
340339
FileHandle* fhc = filehandles[fh-3];
341-
if (fhc == NULL) return -1;
340+
if (fhc == NULL) {
341+
errno = EBADF;
342+
return -1;
343+
}
342344

343345
n = fhc->write(buffer, length);
344346
if (n < 0) {
@@ -359,7 +361,6 @@ extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int
359361
#endif
360362
int n; // n is the number of bytes read
361363

362-
errno = EBADF;
363364
if (fh < 3) {
364365
// only read a character at a time from stdin
365366
#if DEVICE_SERIAL
@@ -390,7 +391,10 @@ extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int
390391
n = 1;
391392
} else {
392393
FileHandle* fhc = filehandles[fh-3];
393-
if (fhc == NULL) return -1;
394+
if (fhc == NULL) {
395+
errno = EBADF;
396+
return -1;
397+
}
394398

395399
n = fhc->read(buffer, length);
396400
if (n < 0) {
@@ -410,51 +414,69 @@ extern "C" int PREFIX(_istty)(FILEHANDLE fh)
410414
extern "C" int _isatty(FILEHANDLE fh)
411415
#endif
412416
{
413-
errno = EBADF;
414417
/* stdin, stdout and stderr should be tty */
415418
if (fh < 3) return 1;
416419

417420
FileHandle* fhc = filehandles[fh-3];
418-
if (fhc == NULL) return -1;
421+
if (fhc == NULL) {
422+
errno = EBADF;
423+
return 0;
424+
}
419425

420-
int err = fhc->isatty();
421-
if (err < 0) {
422-
errno = -err;
423-
return -1;
424-
} else {
426+
int tty = fhc->isatty();
427+
if (tty < 0) {
428+
errno = -tty;
425429
return 0;
430+
} else {
431+
return tty;
426432
}
427433
}
428434

429435
extern "C"
430436
#if defined(__ARMCC_VERSION)
431-
int _sys_seek(FILEHANDLE fh, long position)
437+
int _sys_seek(FILEHANDLE fh, long offset)
432438
#elif defined(__ICCARM__)
433439
long __lseek(int fh, long offset, int whence)
434440
#else
435441
int _lseek(FILEHANDLE fh, int offset, int whence)
436442
#endif
437443
{
438-
errno = EBADF;
439-
if (fh < 3) return 0;
444+
#if defined(__ARMCC_VERSION)
445+
int whence = SEEK_SET;
446+
#endif
447+
if (fh < 3) {
448+
errno = ESPIPE;
449+
return -1;
450+
}
440451

441452
FileHandle* fhc = filehandles[fh-3];
442-
if (fhc == NULL) return -1;
453+
if (fhc == NULL) {
454+
errno = EBADF;
455+
return -1;
456+
}
443457

444-
#if defined(__ARMCC_VERSION)
445-
return fhc->seek(position, SEEK_SET);
446-
#else
447-
return fhc->seek(offset, whence);
448-
#endif
458+
off_t off = fhc->seek(offset, whence);
459+
if (off < 0) {
460+
errno = -off;
461+
return -1;
462+
}
463+
// Assuming INT_MAX = LONG_MAX, so we don't care about prototype difference
464+
if (off > INT_MAX) {
465+
errno = EOVERFLOW;
466+
return -1;
467+
}
468+
return off;
449469
}
450470

451471
#ifdef __ARMCC_VERSION
452472
extern "C" int PREFIX(_ensure)(FILEHANDLE fh) {
453-
errno = EBADF;
454473
if (fh < 3) return 0;
455474

456475
FileHandle* fhc = filehandles[fh-3];
457-
if (fhc == NULL) return -1;
476+
if (fhc == NULL) {
477+
errno = EBADF;
478+
return -1;
479+
}
458480

459481
int err = fhc->sync();
460482
if (err < 0) {
@@ -466,13 +488,27 @@ extern "C" int PREFIX(_ensure)(FILEHANDLE fh) {
466488
}
467489

468490
extern "C" long PREFIX(_flen)(FILEHANDLE fh) {
469-
errno = EBADF;
470-
if (fh < 3) return 0;
491+
if (fh < 3) {
492+
errno = EINVAL;
493+
return -1;
494+
}
471495

472496
FileHandle* fhc = filehandles[fh-3];
473-
if (fhc == NULL) return -1;
497+
if (fhc == NULL) {
498+
errno = EBADF;
499+
return -1;
500+
}
474501

475-
return fhc->size();
502+
off_t size = fhc->size();
503+
if (size < 0) {
504+
errno = -size;
505+
return -1;
506+
}
507+
if (size > LONG_MAX) {
508+
errno = EOVERFLOW;
509+
return -1;
510+
}
511+
return size;
476512
}
477513
#endif
478514

@@ -491,10 +527,12 @@ extern "C" int _fstat(int fd, struct stat *st) {
491527
namespace std {
492528
extern "C" int remove(const char *path) {
493529
#if MBED_CONF_FILESYSTEM_PRESENT
494-
errno = EBADF;
495530
FilePath fp(path);
496531
FileSystem *fs = fp.fileSystem();
497-
if (fs == NULL) return -1;
532+
if (fs == NULL) {
533+
errno = ENOENT;
534+
return -1;
535+
}
498536

499537
int err = fs->remove(fp.fileName());
500538
if (err < 0) {
@@ -511,14 +549,21 @@ extern "C" int remove(const char *path) {
511549

512550
extern "C" int rename(const char *oldname, const char *newname) {
513551
#if MBED_CONF_FILESYSTEM_PRESENT
514-
errno = EBADF;
515552
FilePath fpOld(oldname);
516553
FilePath fpNew(newname);
517554
FileSystem *fsOld = fpOld.fileSystem();
518555
FileSystem *fsNew = fpNew.fileSystem();
519556

557+
if (fsOld == NULL) {
558+
errno = ENOENT;
559+
return -1;
560+
}
561+
520562
/* rename only if both files are on the same FS */
521-
if (fsOld != fsNew || fsOld == NULL) return -1;
563+
if (fsOld != fsNew) {
564+
errno = EXDEV;
565+
return -1;
566+
}
522567

523568
int err = fsOld->rename(fpOld.fileName(), fpNew.fileName());
524569
if (err < 0) {
@@ -552,11 +597,12 @@ extern "C" char *_sys_command_string(char *cmd, int len) {
552597

553598
extern "C" DIR *opendir(const char *path) {
554599
#if MBED_CONF_FILESYSTEM_PRESENT
555-
errno = EBADF;
556-
557600
FilePath fp(path);
558601
FileSystem* fs = fp.fileSystem();
559-
if (fs == NULL) return NULL;
602+
if (fs == NULL) {
603+
errno = ENOENT;
604+
return NULL;
605+
}
560606

561607
Dir *dir = new ManagedDir;
562608
int err = dir->open(fs, fp.fileName());
@@ -903,7 +949,25 @@ void mbed_set_unbuffered_stream(FILE *_file) {
903949
#endif
904950
}
905951

906-
int mbed_getc(FILE *_file){
952+
/* Applications are expected to use fdopen()
953+
* not this function directly. This code had to live here because FILE and FileHandle
954+
* processes are all linked together here.
955+
*/
956+
std::FILE *mbed_fdopen(FileHandle *fh, const char *mode)
957+
{
958+
char buf[12]; /* :0x12345678 + null byte */
959+
std::sprintf(buf, ":%p", fh);
960+
std::FILE *stream = std::fopen(buf, mode);
961+
/* newlib-nano doesn't appear to ever call _isatty itself, so
962+
* happily fully buffers an interactive stream. Deal with that here.
963+
*/
964+
if (stream && fh->isatty()) {
965+
mbed_set_unbuffered_stream(stream);
966+
}
967+
return stream;
968+
}
969+
970+
int mbed_getc(std::FILE *_file){
907971
#if defined (__ICCARM__)
908972
/*This is only valid for unbuffered streams*/
909973
int res = std::fgetc(_file);

0 commit comments

Comments
 (0)