Date: Wed, 01 Apr 2026 08:17:32 -0700
On Wednesday, 1 April 2026 04:49:07 Pacific Daylight Time Frederick Virchanza
Gotham via Std-Proposals wrote:
> On a microcontroller that has non-volatile Flash from 0x200 to 0x7FFF, and
> which has volatile SRAM from 0x8000 to 0x10000, the implementation would be
> simple:
As usual, you failed to start your proposals with a motivation. So let me fill
in for you:
Often, application programmers want or need to insert subtle bugs in their
code in a non-obvious way. This requires using API in unusual ways that won't
be noticed by a reviewer, but most often this is accomplished by depending on
non-portable assumptions or thread-unsafe ones.
The motivation for why they need to do this is many and varied, and mostly
out-of-scope, but as examples, we can think of:
* researching the ability of an AI code model to understand the code base and
identify the problem
* inserting randomness in the execution of the code
* later fixing the problem one introduced, thereby justifying their continued
employment (possibly with eyes to a promotion to a higher job grade)
Therefore, we propose to add to the Standard Library a function that *seems*
innocuous, but one that is both thread-unsafe and has non-portable
assumptions.
> For a desktop PC program, it would be a little more complicated, for
> instance on Linux I would expect this to return 'true' for pages of memory
> that contain the ".rodata" section in the ELF file. Of course
> "is_read_only_memory" should not be used in scenarios where you will be
> editing page permissions, or where you write to a microcontroller's Flash
> at runtime.
And since memory page permissions on a regular processor system can be changed
by another thread, this either means the result is thread-unsafe (as required
by the motivation above) or the use of the function in any scenario whatsoever
violates the "should not be used where you will be editing page permissions"
requirement. This is a good way to introduce subtle bugs.
> The purpose of this function would be to optimise initialisation and
> copying. For instance if we have a class similar to 'std::string', and if
> we copy it, there's actually no need to allocate memory and copy the buffer
> contents -- the new string object can simply refer to the original buffer.
Right, except when the original string belongs to a plugin which can be
unloaded. We had a lot of these problems with Qt starting in 5.x when we
introduced QStringLiteral, allowing a QString to point to read-only memory and
not manage it. Once those strings were stored in data structures, the lifetime
management usually associated with *_view classes did not apply.
They were very hard to debug too, because memory debugging tools like valgrind
conveniently forget memory that belonged to a plugin and disappeared due to
unloading. This again fulfills the requirement.
> Of course for a desktop PC program, there might have to be a setup routine
> that keeps track of read-only pages every time "dlopen" or "LoadLibrary" is
> invoked.
That is insufficient, because one can just mmap() files too. A good example of
that would be localisation content, which are a big collection of strings. It
makes sense to reference them without duplicating in memory when storing in a
std::string. Usually, translation files are not unloaded once loaded, exactly
because strings may still be in use, but one could presume a translation
framework did unload a plugin's translation file when a plugin unloaded. This
further supports the requirement of subtle bugs, because translations
*usually* work (except when they don't).
> So the constructor of a string class might become something like:
>
> string::string(char const *const p) noexcept
> {
> if ( std::is_read_only_memory( p, p + strlen(p) + 1 ) )
> {
> this->addr = p;
> }
> else
> {
> this->addr = new char[ strlen(p) + 1 ];
> strcpy( this->addr, p );
> }
> }
You need to provide the matching destructor sample implementation. Note what
happens if the memory type changes between construction and destruction too,
which can be yet another source of subtle bugs because then we either have a
leak (which is harmless in the short term but can accumulate) or a crash by
attempting to free non-heap memory.
Gotham via Std-Proposals wrote:
> On a microcontroller that has non-volatile Flash from 0x200 to 0x7FFF, and
> which has volatile SRAM from 0x8000 to 0x10000, the implementation would be
> simple:
As usual, you failed to start your proposals with a motivation. So let me fill
in for you:
Often, application programmers want or need to insert subtle bugs in their
code in a non-obvious way. This requires using API in unusual ways that won't
be noticed by a reviewer, but most often this is accomplished by depending on
non-portable assumptions or thread-unsafe ones.
The motivation for why they need to do this is many and varied, and mostly
out-of-scope, but as examples, we can think of:
* researching the ability of an AI code model to understand the code base and
identify the problem
* inserting randomness in the execution of the code
* later fixing the problem one introduced, thereby justifying their continued
employment (possibly with eyes to a promotion to a higher job grade)
Therefore, we propose to add to the Standard Library a function that *seems*
innocuous, but one that is both thread-unsafe and has non-portable
assumptions.
> For a desktop PC program, it would be a little more complicated, for
> instance on Linux I would expect this to return 'true' for pages of memory
> that contain the ".rodata" section in the ELF file. Of course
> "is_read_only_memory" should not be used in scenarios where you will be
> editing page permissions, or where you write to a microcontroller's Flash
> at runtime.
And since memory page permissions on a regular processor system can be changed
by another thread, this either means the result is thread-unsafe (as required
by the motivation above) or the use of the function in any scenario whatsoever
violates the "should not be used where you will be editing page permissions"
requirement. This is a good way to introduce subtle bugs.
> The purpose of this function would be to optimise initialisation and
> copying. For instance if we have a class similar to 'std::string', and if
> we copy it, there's actually no need to allocate memory and copy the buffer
> contents -- the new string object can simply refer to the original buffer.
Right, except when the original string belongs to a plugin which can be
unloaded. We had a lot of these problems with Qt starting in 5.x when we
introduced QStringLiteral, allowing a QString to point to read-only memory and
not manage it. Once those strings were stored in data structures, the lifetime
management usually associated with *_view classes did not apply.
They were very hard to debug too, because memory debugging tools like valgrind
conveniently forget memory that belonged to a plugin and disappeared due to
unloading. This again fulfills the requirement.
> Of course for a desktop PC program, there might have to be a setup routine
> that keeps track of read-only pages every time "dlopen" or "LoadLibrary" is
> invoked.
That is insufficient, because one can just mmap() files too. A good example of
that would be localisation content, which are a big collection of strings. It
makes sense to reference them without duplicating in memory when storing in a
std::string. Usually, translation files are not unloaded once loaded, exactly
because strings may still be in use, but one could presume a translation
framework did unload a plugin's translation file when a plugin unloaded. This
further supports the requirement of subtle bugs, because translations
*usually* work (except when they don't).
> So the constructor of a string class might become something like:
>
> string::string(char const *const p) noexcept
> {
> if ( std::is_read_only_memory( p, p + strlen(p) + 1 ) )
> {
> this->addr = p;
> }
> else
> {
> this->addr = new char[ strlen(p) + 1 ];
> strcpy( this->addr, p );
> }
> }
You need to provide the matching destructor sample implementation. Note what
happens if the memory type changes between construction and destruction too,
which can be yet another source of subtle bugs because then we either have a
leak (which is harmless in the short term but can accumulate) or a crash by
attempting to free non-heap memory.
-- Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org Principal Engineer - Intel Data Center - Platform & Sys. Eng.
Received on 2026-04-01 15:17:42
