Re: Increased RAM usage after upgrade to newlib 4.3.0

Sebastian Huber <[email protected]> Mon, 9 Feb 2026 09:44:27 +0100 (CET)
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
----- Am 2. Feb 2026 um 12:09 schrieb Richard Earnshaw (foss) [email protected]:

> On 02/02/2026 10:44, Pavel V. Melnikov wrote:
>> On Thu, 22 Jan 2026 at 13:43, Richard Earnshaw (foss)
>> <[email protected]> wrote:
>>>
>>> On 20/01/2026 10:44, Pavel V. Melnikov wrote:
>>>> Dear Sebastian and newlib group!
>>>>
>>>> While trying to upgrade my ARM toolchain from GCC 9 to 12, I've
>>>> encountered the same problem that is discussed in this thread, i.e.
>>>> RAM usage suddenly increased by around 300b without changes in the
>>>> code and compiler flags. I traced it to an extra __sf symbol in the
>>>> linker map file. I couldn't find any non-hacky solution online, but
>>>> found some people encountering it as well, e.g. here:
>>>> https://stackoverflow.com/questions/78635407
>>>>
>>>> In my project I don't use stdio functions, and __sf objects are pulled
>>>> if I use `snprintf` function, which, to my understanding, does not
>>>> need stdio FDs to work. It seems it's used because it's referenced in
>>>> impure.c and reent implementation.
>>>> I'm using an ARM MCU with only 4Kb of RAM and would very much like to
>>>> avoid spending extra 300b on things I don't use.
>>>> My question is whether there was any development on this since this
>>>> topic was raised in 2023. Can you suggest a way to drop the stdio fds
>>>> when not using stdio in newer newlib (4.3+)? Since you mentioned it's
>>>> a regression, could this be considered for a fix in future versions?
>>>>
>>>
>>> If you write out a linker map during the linking step you should be able to work
>>> out the chain of dependencies to the functions you're not expecting.  If
>>> linking using GCC as the driver just add -Wl,-Map=<mapfile> to your linker
>>> options.
>> 
>> Hello Richard,
>> 
>> On Thu, 22 Jan 2026 at 13:43, Richard Earnshaw (foss)
>> <[email protected]> wrote:
>>>
>>> If you write out a linker map during the linking step you should be able to work
>>> out the chain of dependencies to the functions you're not expecting.  If
>>> linking using GCC as the driver just add -Wl,-Map=<mapfile> to your linker
>>> options.
>>>
>> 
>> Thanks for your suggestion. I was able to trace the symbol usage to
>> _impure_data array, which is used by vsnprintf function (via
>> _impure_ptr). So, I learned that non-file sprintf is implemented using
>> file-based printf, which in turn pulls the global reentrancy structure
>> with the FDs. So it doesn't look like I can get rid of __sf while
>> still using sprintf function family in current newlib. At the moment I
>> decided to stay at GCC 10 as it has decently modern c++20 support and
>> comes with older newlib 4.2 that doesn't have this issue.
>> 
> 
> Interesting.  I don't have time to look into this in detail, but from your
> description and looking at the changes that went into 4.3, the following is
> where I'd start looking:
> 
> commit b0cb9f85ca3626e0e68fd451c3090d253ceb4300
> Author: Sebastian Huber <[email protected]>
> Date:   Tue May 17 18:28:52 2022 +0200
> 
>    Use global stdio streams for all configurations
> 
> 
> But both Sebastian and Matt Joyce made a number of changes to the printf code
> that year and this might be caused by any one of them, or perhaps by another
> change that I haven't spotted.
> 
> Hopefully, somebody can find some time to get to the bottom of this.

A lot of functions use errno, so you end up with a reference to _REENT.

Yes, the change above causes a memory size regression, however, it addressed also some issues:

commit b0cb9f85ca3626e0e68fd451c3090d253ceb4300
Author: Sebastian Huber <[email protected]>
Date:   Tue May 17 18:28:52 2022 +0200

    Use global stdio streams for all configurations
    
    The _REENT_GLOBAL_STDIO_STREAMS was introduced by commit
    668a4c8722090fffd10869dbb15b879651c1370d in 2017.  Since then it was enabled by
    default for RTEMS.  Recently, the option was enabled for Cygwin which
    previously used an alternative implementation to use global stdio streams.
    
    In Newlib, the stdio streams are defined to thread-specific pointers
    _reent::_stdin, _reent::_stdout and _reent::_stderr.  If the option is disabled
    (the default for most systems), then these pointers are initialized to
    thread-specific FILE objects which use file descriptors 0, 1, and 2,
    respectively.  There are at least three problems with this:
    
    (1) The thread-specific FILE objects are closed by _reclaim_reent().  This
        leads to problems with language run-time libraries that provide wrappers to
        the C/POSIX stdio streams (for example C++ and Ada), since they use the
        thread-specific FILE objects of the initialization thread.  In case the
        initialization thread is deleted, then they use freed memory.
    
    (2) Since thread-specific FILE objects are used with a common output device via
        file descriptors 0, 1 and 2, the locking at FILE object level cannot ensure
        atomicity of the output, e.g. a call to printf().
    
    (3) There are resource managment issues, see:
    
        https://sourceware.org/pipermail/newlib/2022/019558.html
    
        https://bugs.linaro.org/show_bug.cgi?id=5841
    
    This patch enables the _REENT_GLOBAL_STDIO_STREAMS behaviour for all Newlib
    configurations and removes the option.  This removes a couple of #ifdef blocks.

I guess, the memory size regression is relevant to the _REENT_SMALL configuration? How big is it?

One option would be to initialize the stdio streams in _REENT to NULL and then initialize them on demand in _REENT_SMALL_CHECK_INIT().

For a size constraint environment, using the _REENT_THREAD_LOCAL option is probably the best approach in Newlib.

-- 
embedded brains GmbH & Co. KG
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: [email protected]
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/