public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* Initialization order issues related to std::cout and inline variables
@ 2024-05-11  9:42 Jan Schultke
  2024-05-11 15:17 ` Jonathan Wakely
  0 siblings, 1 reply; 4+ messages in thread
From: Jan Schultke @ 2024-05-11  9:42 UTC (permalink / raw)
  To: libstdc++

Hi, I've realized that according to the current wording in the
standard, and with the current implementation in libstdc++, there is
no reliable way to initialize std::cout before dynamic init of inline
variables:

> // included from <iostream>:
> namespace std {
> // ...
> extern ostream cout;
> // libstdc++ implementation detail; initializes cout:
> static ios_base::Init __ioinit;
> }
>
> // then, in our own code, possibly a header:
> inline int x = [] {
>    std::cout << "awoo"; // possibly UB
>    return 0;
> }();

It would be fine if std::cout was inline, and it would be fine if x
was non-inline, but only x being inline makes its initialization
indeterminately sequenced, even if <iostream> is always included prior
to wherever x is defined. This is very strange, and I think we should
do something about it.

- Is this a known issue in the committee? Is this defect-worthy?
- Could we make std::cout inline without breaking anything so that
this would become valid?

See https://stackoverflow.com/q/78463564/5740428 for someone running
into an issue with this (using clang, not GCC), and see the answer in
that Q&A for an in-depth explanation of wording and why this happens.

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

* Re: Initialization order issues related to std::cout and inline variables
  2024-05-11  9:42 Initialization order issues related to std::cout and inline variables Jan Schultke
@ 2024-05-11 15:17 ` Jonathan Wakely
  2024-05-11 16:14   ` Jan Schultke
  0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Wakely @ 2024-05-11 15:17 UTC (permalink / raw)
  To: Jan Schultke; +Cc: libstdc++

[-- Attachment #1: Type: text/plain, Size: 1863 bytes --]

On Sat, 11 May 2024, 10:43 Jan Schultke, <janschultke@googlemail.com> wrote:

> Hi, I've realized that according to the current wording in the
> standard, and with the current implementation in libstdc++, there is
> no reliable way to initialize std::cout before dynamic init of inline
> variables:
>
> > // included from <iostream>:
> > namespace std {
> > // ...
> > extern ostream cout;
> > // libstdc++ implementation detail; initializes cout:
> > static ios_base::Init __ioinit;
> > }
> >
> > // then, in our own code, possibly a header:
> > inline int x = [] {
> >    std::cout << "awoo"; // possibly UB
> >    return 0;
> > }();
>
> It would be fine if std::cout was inline, and it would be fine if x
> was non-inline, but only x being inline makes its initialization
> indeterminately sequenced, even if <iostream> is always included prior
> to wherever x is defined. This is very strange, and I think we should
> do something about it.
>
> - Is this a known issue in the committee?


I don't think I've seen it discussed.

Is this defect-worthy?
>

Probably yes.

- Could we make std::cout inline without breaking anything so that
> this would become valid?
>

No, I don't think so.

The constructor of cout doesn't do anything, it's the ios::Init constructor
that initializes things. That has an init priority attribute, so I'd be
surprised if the inline variable gets created first when using libstdc++.
That seems like a bug if it does.




> See https://stackoverflow.com/q/78463564/5740428 for someone running
> into an issue with this (using clang, not GCC), and see the answer in
> that Q&A for an in-depth explanation of wording and why this happens.
>

Your explanation seems based on older versions of libstdc++, as we don't
have an ios::Init object there now. There's only one stuck object,
initialized inside libstdc++.so when that's loaded.

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

* Re: Initialization order issues related to std::cout and inline variables
  2024-05-11 15:17 ` Jonathan Wakely
@ 2024-05-11 16:14   ` Jan Schultke
  2024-05-11 16:38     ` Jonathan Wakely
  0 siblings, 1 reply; 4+ messages in thread
From: Jan Schultke @ 2024-05-11 16:14 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++

> That has an init priority attribute, so I'd be surprised if the inline variable gets created first when using libstdc++

From the source code, it looks like the __iosinit object is still used
when the attribute isn't available. The issue specifically occurred
with clang 15 and libstdc++, so I guess the attribute didn't exist in
clang back then, or libstdc++ didn't have that option yet.

I've also been informed that adding your own "inline
std::ios_base::Init init;" declaration solves the problem, but if the
<iostream>'s __iosinit was inline, you wouldn't need this in the first
place. However, doing that is presumably not allowed with the current
wording, since inline gives you partially-ordered initialization, not
ordered.

Anyhow, while it probably is a little bit defective, the specific
issue with std::cout seems to have been solved in all standard
libraries. It would still be nice to have more ordering where it makes
sense (i.e. between ordered initialization and partially-ordered
initialization variables). I've sent a mail to Richard Smith (who
wrote this wording, presumably) to check whether it's intentional
design. Until then, not sure what to do, if anything.

On Sat, May 11, 2024 at 5:18 PM Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
>
>
>
> On Sat, 11 May 2024, 10:43 Jan Schultke, <janschultke@googlemail.com> wrote:
>>
>> Hi, I've realized that according to the current wording in the
>> standard, and with the current implementation in libstdc++, there is
>> no reliable way to initialize std::cout before dynamic init of inline
>> variables:
>>
>> > // included from <iostream>:
>> > namespace std {
>> > // ...
>> > extern ostream cout;
>> > // libstdc++ implementation detail; initializes cout:
>> > static ios_base::Init __ioinit;
>> > }
>> >
>> > // then, in our own code, possibly a header:
>> > inline int x = [] {
>> >    std::cout << "awoo"; // possibly UB
>> >    return 0;
>> > }();
>>
>> It would be fine if std::cout was inline, and it would be fine if x
>> was non-inline, but only x being inline makes its initialization
>> indeterminately sequenced, even if <iostream> is always included prior
>> to wherever x is defined. This is very strange, and I think we should
>> do something about it.
>>
>> - Is this a known issue in the committee?
>
>
> I don't think I've seen it discussed.
>
>> Is this defect-worthy?
>
>
> Probably yes.
>
>> - Could we make std::cout inline without breaking anything so that
>> this would become valid?
>
>
> No, I don't think so.
>
> The constructor of cout doesn't do anything, it's the ios::Init constructor that initializes things. That has an init priority attribute, so I'd be surprised if the inline variable gets created first when using libstdc++. That seems like a bug if it does.
>
>
>
>>
>> See https://stackoverflow.com/q/78463564/5740428 for someone running
>> into an issue with this (using clang, not GCC), and see the answer in
>> that Q&A for an in-depth explanation of wording and why this happens.
>
>
> Your explanation seems based on older versions of libstdc++, as we don't have an ios::Init object there now. There's only one stuck object, initialized inside libstdc++.so when that's loaded.
>
>

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

* Re: Initialization order issues related to std::cout and inline variables
  2024-05-11 16:14   ` Jan Schultke
@ 2024-05-11 16:38     ` Jonathan Wakely
  0 siblings, 0 replies; 4+ messages in thread
From: Jonathan Wakely @ 2024-05-11 16:38 UTC (permalink / raw)
  To: Jan Schultke; +Cc: libstdc++

[-- Attachment #1: Type: text/plain, Size: 3637 bytes --]

On Sat, 11 May 2024, 17:14 Jan Schultke, <janschultke@googlemail.com> wrote:

> > That has an init priority attribute, so I'd be surprised if the inline
> variable gets created first when using libstdc++
>
> From the source code, it looks like the __iosinit object is still used
> when the attribute isn't available. The issue specifically occurred
> with clang 15 and libstdc++, so I guess the attribute didn't exist in
> clang back then, or libstdc++ didn't have that option yet.
>

The attribute doesn't work on macOS, but works on nearly all other systems.


> I've also been informed that adding your own "inline
> std::ios_base::Init init;" declaration solves the problem, but if the
> <iostream>'s __iosinit was inline, you wouldn't need this in the first
> place. However, doing that is presumably not allowed with the current
> wording, since inline gives you partially-ordered initialization, not
> ordered.
>
> Anyhow, while it probably is a little bit defective, the specific
> issue with std::cout seems to have been solved in all standard
> libraries. It would still be nice to have more ordering where it makes
> sense (i.e. between ordered initialization and partially-ordered
> initialization variables). I've sent a mail to Richard Smith (who
> wrote this wording, presumably) to check whether it's intentional
> design. Until then, not sure what to do, if anything.
>
> On Sat, May 11, 2024 at 5:18 PM Jonathan Wakely <jwakely.gcc@gmail.com>
> wrote:
> >
> >
> >
> > On Sat, 11 May 2024, 10:43 Jan Schultke, <janschultke@googlemail.com>
> wrote:
> >>
> >> Hi, I've realized that according to the current wording in the
> >> standard, and with the current implementation in libstdc++, there is
> >> no reliable way to initialize std::cout before dynamic init of inline
> >> variables:
> >>
> >> > // included from <iostream>:
> >> > namespace std {
> >> > // ...
> >> > extern ostream cout;
> >> > // libstdc++ implementation detail; initializes cout:
> >> > static ios_base::Init __ioinit;
> >> > }
> >> >
> >> > // then, in our own code, possibly a header:
> >> > inline int x = [] {
> >> >    std::cout << "awoo"; // possibly UB
> >> >    return 0;
> >> > }();
> >>
> >> It would be fine if std::cout was inline, and it would be fine if x
> >> was non-inline, but only x being inline makes its initialization
> >> indeterminately sequenced, even if <iostream> is always included prior
> >> to wherever x is defined. This is very strange, and I think we should
> >> do something about it.
> >>
> >> - Is this a known issue in the committee?
> >
> >
> > I don't think I've seen it discussed.
> >
> >> Is this defect-worthy?
> >
> >
> > Probably yes.
> >
> >> - Could we make std::cout inline without breaking anything so that
> >> this would become valid?
> >
> >
> > No, I don't think so.
> >
> > The constructor of cout doesn't do anything, it's the ios::Init
> constructor that initializes things. That has an init priority attribute,
> so I'd be surprised if the inline variable gets created first when using
> libstdc++. That seems like a bug if it does.
> >
> >
> >
> >>
> >> See https://stackoverflow.com/q/78463564/5740428 for someone running
> >> into an issue with this (using clang, not GCC), and see the answer in
> >> that Q&A for an in-depth explanation of wording and why this happens.
> >
> >
> > Your explanation seems based on older versions of libstdc++, as we don't
> have an ios::Init object there now. There's only one stuck object,
> initialized inside libstdc++.so when that's loaded.
> >
> >
>

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

end of thread, other threads:[~2024-05-11 16:38 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-05-11  9:42 Initialization order issues related to std::cout and inline variables Jan Schultke
2024-05-11 15:17 ` Jonathan Wakely
2024-05-11 16:14   ` Jan Schultke
2024-05-11 16:38     ` Jonathan Wakely

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).