public inbox for newlib@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Fix stdio memory leaks with _REENT_SMALL + _LITE_EXIT
@ 2022-04-12 13:23 Volodymyr Medvid
  2022-04-12 16:10 ` Sebastian Huber
  0 siblings, 1 reply; 3+ messages in thread
From: Volodymyr Medvid @ 2022-04-12 13:23 UTC (permalink / raw)
  To: newlib

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


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Fix stdio memory leaks with _REENT_SMALL + _LITE_EXIT
  2022-04-12 13:23 [PATCH] Fix stdio memory leaks with _REENT_SMALL + _LITE_EXIT Volodymyr Medvid
@ 2022-04-12 16:10 ` Sebastian Huber
  2022-04-12 20:57   ` Volodymyr Medvid
  0 siblings, 1 reply; 3+ messages in thread
From: Sebastian Huber @ 2022-04-12 16:10 UTC (permalink / raw)
  To: Volodymyr Medvid, newlib

On 12/04/2022 15:23, Volodymyr Medvid wrote:
> 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).

Yes, this is the Newlib design. FILE objects are never freed. If you 
close a FILE object, then it is basically placed on a free list and 
recycled once another FILE object is opened.

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

This is definitely not the right way to address this issue.

Why don't you use the _REENT_GLOBAL_STDIO_STREAMS Newlib configuration 
option?

> 
> 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 forhttps://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)

This patch would break at least RTEMS.

-- 
embedded brains GmbH
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.huber@embedded-brains.de
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

Registergericht: Amtsgericht München
Registernummer: HRB 157899
Vertretungsberechtigte Geschäftsführer: Peter Rasmussen, Thomas Dörfler
Unsere Datenschutzerklärung finden Sie hier:
https://embedded-brains.de/datenschutzerklaerung/

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Fix stdio memory leaks with _REENT_SMALL + _LITE_EXIT
  2022-04-12 16:10 ` Sebastian Huber
@ 2022-04-12 20:57   ` Volodymyr Medvid
  0 siblings, 0 replies; 3+ messages in thread
From: Volodymyr Medvid @ 2022-04-12 20:57 UTC (permalink / raw)
  To: Sebastian Huber; +Cc: newlib

On Tue, 12 Apr 2022 18:10:38 +0200
Sebastian Huber <sebastian.huber@embedded-brains.de> wrote:

> This is definitely not the right way to address this issue.
>
> Why don't you use the _REENT_GLOBAL_STDIO_STREAMS Newlib
> configuration option?

Thanks for the suggestion - I was able to verify the memory leak goes away once
newlib-nano is reconfigured with "--enable-newlib-global-stdio-streams".
I also see you originally submitted commit
668a4c8722090fffd10869dbb15b879651c1370d
that was later extended to also apply to _REENT_SMALL
(b7520b14d5fe175d9bc60266700fb7b988600a84).
I filed a ticket https://bugs.linaro.org/show_bug.cgi?id=5841 to
enable global stdio
streams for standard newlib-nano provided with GNU Arm Embedded
toolchain binary package.

> This patch would break at least RTEMS.
>

Sorry, I have no way to validate this on any platform except Arm
Cortex-M + FreeRTOS.
Also, the current test suite is not capable of catching issues with
stdio reentrancy.
I understand there are lot of platform/OS-specific stdio
implementations, some of them
may rely on configure flags like "--enable-newlib-reent-small" or
"--enable-lite-exit"
to meet the memory and performance constraints. Unfortunately, it is
not clear from
the commit e7565f10886bac86410db6eb6fda47da1d04ac9b why _fclose_r was changed to
_fflush_r when _LITE_EXIT is enabled - is this to reduce memory footprint?

Thanks,
Volodymyr

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-04-12 20:57 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-12 13:23 [PATCH] Fix stdio memory leaks with _REENT_SMALL + _LITE_EXIT Volodymyr Medvid
2022-04-12 16:10 ` Sebastian Huber
2022-04-12 20:57   ` Volodymyr Medvid

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).