Merge branch 'bugfix/newlib_fd_memory_leak' into 'master'

override per-task __cleanup handler to close stdin, stdout, stderr

Default _cleanup_r function (called from _reclaim_reent) calls _fclose_r for all file descriptors related to a particular instance of struct _reent.
It does that by calling _fwalk_reent, which iterates over __sglue list in struct _reent and calls _fclose_r for each member. But _stdin, _stdout, and _stderr are not in this list, so _fclose_r is not called for them. Which leads to a memory leak.
The easy way to fix this is to reset __cleanup member of struct _reent to our new “patched” version, which first calls the original version (_cleanup_r) and then does _fclose_r for each of the stdin, stdout, and stderr.

See merge request !94
This commit is contained in:
Ivan Grokhotkov 2016-09-20 12:12:06 +08:00
commit 6ca02748ac
2 changed files with 22 additions and 0 deletions

View file

@ -367,6 +367,23 @@ void IRAM_ATTR _lock_release_recursive(_lock_t *lock) {
lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
}
// This function is not part on newlib API, it is defined in libc/stdio/local.h
// It is called as part of _reclaim_reent via a pointer in __cleanup member
// of struct _reent.
// This function doesn't call _fclose_r for _stdin, _stdout, _stderr members
// of struct reent. Not doing so causes a memory leak each time a task is
// terminated. We replace __cleanup member with _extra_cleanup_r (below) to work
// around this.
extern void _cleanup_r(struct _reent* r);
void _extra_cleanup_r(struct _reent* r)
{
_cleanup_r(r);
_fclose_r(r, r->_stdout);
_fclose_r(r, r->_stderr);
_fclose_r(r, r->_stdin);
}
static struct _reent s_reent;
/*

View file

@ -85,6 +85,7 @@ task.h is included from an application file. */
#include "StackMacros.h"
#include "portmacro.h"
#include "semphr.h"
#include "sys/reent.h"
/* Lint e961 and e750 are suppressed as a MISRA exception justified because the
MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
@ -3489,6 +3490,9 @@ TCB_t *pxNewTCB;
#if ( INCLUDE_vTaskDelete == 1 )
// TODO: move this to newlib component and provide a header file
extern void _extra_cleanup_r(struct _reent* r);
static void prvDeleteTCB( TCB_t *pxTCB )
{
/* This call is required specifically for the TriCore port. It must be
@ -3500,6 +3504,7 @@ TCB_t *pxNewTCB;
to the task to free any memory allocated at the application level. */
#if ( configUSE_NEWLIB_REENTRANT == 1 )
{
pxTCB->xNewLib_reent.__cleanup = &_extra_cleanup_r;
_reclaim_reent( &( pxTCB->xNewLib_reent ) );
}
#endif /* configUSE_NEWLIB_REENTRANT */