Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CWG2914 [basic.start.static] Unclear order of initialization of static and thread local variables #559

Open
t3nsor opened this issue Jun 20, 2024 · 6 comments

Comments

@t3nsor
Copy link

t3nsor commented Jun 20, 2024

Full name of submitter: Brian Bi

Issue description: It is heavily implied, but not stated outright, that initialization of all non-local static variables happens before initialization of all non-local thread-local variables. For example, [basic.start.static] seems to refer to initializing variables with static storage duration and thread storage duration as "phases", which may imply that one phase completes before the other starts. [basic.start.term]/2 appears to guarantee that returning from main destroys all thread-local variables of the main thread before destroying any static variables, which would be peculiar if the static variables were not initialized first.

Suggested resolution: Edit [basic.start.static]/1 as shown:

Variables with static storage duration are initialized as a consequence of program initiation. Variables with thread storage duration are initialized as a consequence of thread execution. The initialization of all non-block variables with static storage duration (if any) strongly happens before the initialization of any non-block variable with thread storage duration. Within each of these phases of initiation, initialization occurs as follows.

@randomnetcat
Copy link

randomnetcat commented Jun 20, 2024

The suggested resolution seems too strong. In the case of deferred dynamic initialization, the dynamic initialization should not happen before the initialization of (at least some) thread storage duration variables.

Consider the following example, where whatever() is something that prevents constant-initialization:

// TU A
int a = whatever();
thread_local int b = whatever();

void foo();

int main() {
    foo();
}

// TU B
static int c = whatever();

void foo() { return c; }

My understanding is that initializing a, then b, then c is intended to be permitted in the status quo.

@t3nsor
Copy link
Author

t3nsor commented Jun 20, 2024

OK, how about this.

Edit [basic.start.static]/1:

Variables with static storage duration are initialized as a consequence of program initiation. Variables with thread storage duration are initialized as a consequence of thread execution. All non-deferred ([basic.start.dynamic]) initialization (if any) of non-block variables with static storage duration strongly happens before any non-deferred initialization of non-block variables with thread storage duration. Within each of these phases of initiation, initialization occurs as follows.

Edit [basic.start.dynamic]/5:

It is implementation-defined whether the dynamic initialization of a non-block non-inline variable o with static storage duration is sequenced before the first statement of main or is deferred. If it is deferred, it strongly happens before any non-initialization odr-use of any non-inline function or non-inline variable defined in the same translation unit as the variable to be initialized o and any deferred initialization of non-inline non-block variables with thread storage duration defined in the same translation unit as o.39 It is implementation-defined in which threads and at which points in the program such deferred dynamic initialization occurs.

@randomnetcat
Copy link

randomnetcat commented Jun 20, 2024

Interestingly, static initialization is arguably "non-deferred", so the first paragraph would make static initialization of variables with static storage duration happen before static initialization of variables with thread storage duration. I don't think that's a problem, though?

The second paragraph doesn't appear to ensure that deferred dynamic initialization of variables with thread storage duration happens before an odr-use of a function or variable in the same TU, but I think that's also a problem with the status quo.

Otherwise, I think this looks fine?

@t3nsor
Copy link
Author

t3nsor commented Jun 21, 2024

so the first paragraph would make static initialization of variables with static storage duration happen before static initialization of variables with thread storage duration. I don't think that's a problem, though?

That might be what the status quo is trying to say anyway with its "within each of these phases" wording.

The second paragraph doesn't appear to ensure that deferred dynamic initialization of variables with thread storage duration happens before an odr-use of a function or variable in the same TU

Deferred dynamic initialization of thread local variables is governed by p7. In p5, it's true that adding the suggested guarantee would possibly allow a function in the same TU to observe a thread local variable prior to its dynamic initialization. However, such a use of that function would not be a "non-initialization odr-use" because it would be caused by the initialization of a static variable, so it wouldn't violate p7.

@randomnetcat
Copy link

Ah, yes, sorry. I missed that paragraph. Looks fine then.

@jensmaurer
Copy link
Member

CWG2914

@jensmaurer jensmaurer changed the title [basic.start.static] Unclear order of initialization of static and thread local variables CWG2914 [basic.start.static] Unclear order of initialization of static and thread local variables Jul 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants