public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
@ 2023-01-05 10:51 agriff at tin dot it
  2023-01-05 11:41 ` [Bug c++/108299] " jakub at gcc dot gnu.org
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: agriff at tin dot it @ 2023-01-05 10:51 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

            Bug ID: 108299
           Summary: toplevel thread_local variables are not initialized if
                    not referenced and initialized at wrong moment when
                    referenced
           Product: gcc
           Version: 12.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: agriff at tin dot it
  Target Milestone: ---

The standard mandates that thread_local variables at top level must be
initialized in case anything in the compilation unit is referred to. There is a
specific note on the fact that they must be initialized even if they're not
used in the program.
Also they must be initialized at thread start or before anything from the
compilation unit is accessed by the thread.

This code however shows that g++ doesn't follow this rule

    #include <stdio.h>

    thread_local int flag = ([](){
        printf("HERE!\n");
        return 1;
    })();

    int main() {
        printf("Hello, world.\n");
        return 0;
    }

In this version the thread local initialization is skipped.
Mover if after the printf the statement

    flag;

is added then the initialization is performed, but AFTER the "Hello, world"
message (another violation of the standard).

Trying on godbolt I saw the problem is present even in trunk and in clang
(works as expected in MSVC).

The problems are present both on the main implicit thread and with threads
started explicitly with std::thread.

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

* [Bug c++/108299] toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
  2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
@ 2023-01-05 11:41 ` jakub at gcc dot gnu.org
  2023-01-05 11:41 ` jakub at gcc dot gnu.org
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: jakub at gcc dot gnu.org @ 2023-01-05 11:41 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |RESOLVED
                 CC|                            |jakub at gcc dot gnu.org
         Resolution|---                         |INVALID

--- Comment #1 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
I don't think your claims are based on anything in the standard.
The standard clearly says that it is implementation defined if non-block
thread_local vars are dynamically initialized right away or deferred and
initialized on first non-initialization odr-use.  The latter is what GCC
implements.

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

* [Bug c++/108299] toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
  2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
  2023-01-05 11:41 ` [Bug c++/108299] " jakub at gcc dot gnu.org
@ 2023-01-05 11:41 ` jakub at gcc dot gnu.org
  2023-01-05 14:38 ` agriff at tin dot it
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: jakub at gcc dot gnu.org @ 2023-01-05 11:41 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
See https://eel.is/c++draft/basic.start.dynamic#7 for details.

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

* [Bug c++/108299] toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
  2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
  2023-01-05 11:41 ` [Bug c++/108299] " jakub at gcc dot gnu.org
  2023-01-05 11:41 ` jakub at gcc dot gnu.org
@ 2023-01-05 14:38 ` agriff at tin dot it
  2023-01-05 14:47 ` jakub at gcc dot gnu.org
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: agriff at tin dot it @ 2023-01-05 14:38 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

--- Comment #3 from Andrea Griffini <agriff at tin dot it> ---
Thread storage duration is different from static storage duration.

The text I found on the topic is different from the one you are linking,
but even in this version (that is indeed more permissive) it's explicitly
stated that a thread_local variable must be initialized before any other
thread_local variable is accessed in the same compilation unit.

> it is implementation-defined whether the dynamic initialization of a
> non-block non-inline variable with thread storage duration is sequenced
> before the first statement of the initial function of a thread or is deferred.

> --------------------------------------------------------------------
> If it is deferred, the initialization associated with the entity for thread
> t is sequenced before the first non-initialization odr-use by t of any
> non-inline variable with thread storage duration defined in the same
> translation unit as the variable to be initialized.
> --------------------------------------------------------------------

> It is implementation-defined in which threads and at which points in
> the program such deferred dynamic initialization occurs.

g++ doesn't seem to follow the rule


#include <stdio.h>

thread_local int flag = ([](){
    printf("HERE!\n"); // This initialization never happens
    return 1;
})();

thread_local int flag2;

int main() {
    printf("Hello, world.\n");
    flag2 = 0; // accesses another thread_local variable in same compilation
unit
    return 0;
}

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

* [Bug c++/108299] toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
  2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
                   ` (2 preceding siblings ...)
  2023-01-05 14:38 ` agriff at tin dot it
@ 2023-01-05 14:47 ` jakub at gcc dot gnu.org
  2023-01-05 14:52 ` agriff at tin dot it
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: jakub at gcc dot gnu.org @ 2023-01-05 14:47 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

--- Comment #4 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
flag2 doesn't have dynamic initialization, if you add dynamic initialization to
it, you'll see that flag is constructed before flag2 and that happens before it
is referenced in the current thread (after the printf in main).

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

* [Bug c++/108299] toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
  2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
                   ` (3 preceding siblings ...)
  2023-01-05 14:47 ` jakub at gcc dot gnu.org
@ 2023-01-05 14:52 ` agriff at tin dot it
  2023-01-05 15:17 ` jakub at gcc dot gnu.org
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: agriff at tin dot it @ 2023-01-05 14:52 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

--- Comment #5 from Andrea Griffini <agriff at tin dot it> ---
So you are saying that the standard forgot to add "that requires dynamic
initialization" and that this is the intention?

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

* [Bug c++/108299] toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
  2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
                   ` (4 preceding siblings ...)
  2023-01-05 14:52 ` agriff at tin dot it
@ 2023-01-05 15:17 ` jakub at gcc dot gnu.org
  2023-01-05 15:40 ` redi at gcc dot gnu.org
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: jakub at gcc dot gnu.org @ 2023-01-05 15:17 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jason at gcc dot gnu.org,
                   |                            |redi at gcc dot gnu.org

--- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
CCing C++ committee members.
Requiring that any odr-uses of thread_local vars which have static
initialization (which strongly happens before any dynamic initialization) would
dynamically initialize all thread_local variables in the same TU declared
before such vars would have serious ABI and performance effects for no useful
gains.

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

* [Bug c++/108299] toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
  2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
                   ` (5 preceding siblings ...)
  2023-01-05 15:17 ` jakub at gcc dot gnu.org
@ 2023-01-05 15:40 ` redi at gcc dot gnu.org
  2023-01-05 15:42 ` redi at gcc dot gnu.org
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: redi at gcc dot gnu.org @ 2023-01-05 15:40 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

--- Comment #7 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Comment 0 seems wrong to me, there is no requirement that flag is initialized
if not odr-used, and if it is initialized, it doesn't have to happen before the
printf statement.

I agree that the standard says comment 3 should initialized both thread local
variables.

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

* [Bug c++/108299] toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
  2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
                   ` (6 preceding siblings ...)
  2023-01-05 15:40 ` redi at gcc dot gnu.org
@ 2023-01-05 15:42 ` redi at gcc dot gnu.org
  2023-01-05 15:53 ` agriff at tin dot it
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: redi at gcc dot gnu.org @ 2023-01-05 15:42 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

--- Comment #8 from Jonathan Wakely <redi at gcc dot gnu.org> ---
FWIW the current wording in the standard was introduced by
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0250r3.html

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

* [Bug c++/108299] toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
  2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
                   ` (7 preceding siblings ...)
  2023-01-05 15:42 ` redi at gcc dot gnu.org
@ 2023-01-05 15:53 ` agriff at tin dot it
  2023-01-06 19:57 ` jason at gcc dot gnu.org
  2023-01-06 20:58 ` jakub at gcc dot gnu.org
  10 siblings, 0 replies; 12+ messages in thread
From: agriff at tin dot it @ 2023-01-05 15:53 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

--- Comment #9 from Andrea Griffini <agriff at tin dot it> ---
I agree that comment 0 is wrong and was based on a text that I thought was
taken from the standard but apparently was not (cppreference.com). Sorry for
the noise.

I think that if the dynamic initialization should be tied only to uses of other
thread locals requiring dynamic initialization this should be stated more
precisely in the standard text.

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

* [Bug c++/108299] toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
  2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
                   ` (8 preceding siblings ...)
  2023-01-05 15:53 ` agriff at tin dot it
@ 2023-01-06 19:57 ` jason at gcc dot gnu.org
  2023-01-06 20:58 ` jakub at gcc dot gnu.org
  10 siblings, 0 replies; 12+ messages in thread
From: jason at gcc dot gnu.org @ 2023-01-06 19:57 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

Jason Merrill <jason at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
   Last reconfirmed|                            |2023-01-06
           Assignee|unassigned at gcc dot gnu.org      |jason at gcc dot gnu.org
           Keywords|                            |wrong-code
         Resolution|INVALID                     |---
             Status|RESOLVED                    |ASSIGNED
     Ever confirmed|0                           |1

--- Comment #10 from Jason Merrill <jason at gcc dot gnu.org> ---
(In reply to Jakub Jelinek from comment #6)

Hmm, I don't see the ABI problem: wrappers are comdat/weak and prepared to
handle the absence of an init function, so TUs that either use or don't use
wrappers should be ABI-compatible, though of course you would need both to be
recompiled to get the currently specified behavior.

For performance, the one degradation I see is preventing the PR101786
optimization with extern constinit.

https://github.com/cplusplus/CWG/issues/210

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

* [Bug c++/108299] toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced
  2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
                   ` (9 preceding siblings ...)
  2023-01-06 19:57 ` jason at gcc dot gnu.org
@ 2023-01-06 20:58 ` jakub at gcc dot gnu.org
  10 siblings, 0 replies; 12+ messages in thread
From: jakub at gcc dot gnu.org @ 2023-01-06 20:58 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108299

--- Comment #11 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
You're right.  All we'd need to do is revert PR101786 change and call
__tls_init if in the current TU there are any dynamic TLS initializations when
any TLS var from current TU is referenced, even when it has just static
initializer.

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

end of thread, other threads:[~2023-01-06 20:58 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-05 10:51 [Bug c++/108299] New: toplevel thread_local variables are not initialized if not referenced and initialized at wrong moment when referenced agriff at tin dot it
2023-01-05 11:41 ` [Bug c++/108299] " jakub at gcc dot gnu.org
2023-01-05 11:41 ` jakub at gcc dot gnu.org
2023-01-05 14:38 ` agriff at tin dot it
2023-01-05 14:47 ` jakub at gcc dot gnu.org
2023-01-05 14:52 ` agriff at tin dot it
2023-01-05 15:17 ` jakub at gcc dot gnu.org
2023-01-05 15:40 ` redi at gcc dot gnu.org
2023-01-05 15:42 ` redi at gcc dot gnu.org
2023-01-05 15:53 ` agriff at tin dot it
2023-01-06 19:57 ` jason at gcc dot gnu.org
2023-01-06 20:58 ` jakub at gcc dot gnu.org

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