[PATCH] Fix stdio memory leaks with _REENT_SMALL + _LITE_EXIT

Volodymyr Medvid <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
When a thread calls stdio functions (say, printf) and then dies,
_reclaim_reent() runs cleanup_stdio() to free the file buffers
and descriptors created for this thread. This is causing multiple
memory leaks when newlib is configured with _REENT_SMALL
and _LITE_EXIT - this is the standard configuration for
newlib-nano provided with GNU Arm Embedded Toolchain.

1. While __sfp() allocates the FILE objects in GLOBAL_REENT glue chain,
   stdio_cleanup walks through the thread-specific glue chain
   to run the cleanup_func. Therefore, the FILE objects are never
   freed. This leaks ~428 bytes per thread (glue_with_file + 3 x FILE).

   To fix this, update __sfp() to use the per-thread glue chain for
   stdio descriptors.

2. With _LITE_EXIT enabled, _fflush_r is used as cleanup_func
   instead of _fclose_r - as a result, the I/O buffer memory allocated
   by __smakebuf_r is never freed - this leaks another 1024 bytes.
   To fix this, update cleanup_stdio to always use _fclose_r.

This is a follow-up patch for https://ecos.sourceware.org/ml/newlib/current/017697.html
---
 newlib/libc/stdio/findfp.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/newlib/libc/stdio/findfp.c b/newlib/libc/stdio/findfp.c
index 1370b63b8..2799980f3 100644
--- a/newlib/libc/stdio/findfp.c
+++ b/newlib/libc/stdio/findfp.c
@@ -153,7 +153,7 @@ __sfp (struct _reent *d)
 
   if (_GLOBAL_REENT->__cleanup == NULL)
     __sinit (_GLOBAL_REENT);
-  for (g = &_GLOBAL_REENT->__sglue;; g = g->_next)
+  for (g = &d->__sglue;; g = g->_next)
     {
       for (fp = g->_iobs, n = g->_niobs; --n >= 0; fp++)
 	if (fp->_flags == 0)
@@ -209,14 +209,9 @@ cleanup_stdio (struct _reent *ptr)
      the aforementioned systems. */
   cleanup_func = __sflushw_r;
 #else
-  /* Otherwise close files and flush read streams, too.
-     Note we call flush directly if "--enable-lite-exit" is in effect.  */
-#ifdef _LITE_EXIT
-  cleanup_func = _fflush_r;
-#else
+  /* Otherwise close files and flush read streams, too. */
   cleanup_func = _fclose_r;
 #endif
-#endif
 #ifdef _REENT_GLOBAL_STDIO_STREAMS
   if (ptr->_stdin != &__sf[0])
     (*cleanup_func) (ptr, ptr->_stdin);
-- 
2.25.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.