Are static locals initialized safely?

598 views
Skip to first unread message

Pavel Kalinnikov

unread,
Nov 24, 2016, 7:06:19 AM11/24/16
to c...@chromium.org, Nico Weber, Ilya Sherman
Hi cxx wise folks,

In the list of C++11 features I couldn't find anything about static local variables. The new standard claims they should be thread-safely initialized once. Can we rely on this in chromium?

Thank you,
Pavel

Vasilii Sukhanov

unread,
Nov 24, 2016, 7:34:54 AM11/24/16
to Pavel Kalinnikov, cxx, Nico Weber, Ilya Sherman
It's still prohibited for Chromium (see the C++ Dos and Don'ts). Although the relevant thread is 5 years old.

--
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CADF%2BPP7bQxVu_CnkYrM53FPqfWtNWnOCnzw93%3DNy_%3DisRDhmwQ%40mail.gmail.com.

Mark Mentovai

unread,
Nov 24, 2016, 7:36:45 AM11/24/16
to Pavel Kalinnikov, cxx, Nico Weber, Ilya Sherman
Normally they are available in standard C++11, but this is not true in Chromium.


Background: When Chromium was an infant, MSVC had no support for thread-safe statics. (This was pre-C++11, so you couldn’t really blame them for this omission.) We had to come up with other ways to initialize these variables safely, like LazyInstance and Singleton. When we started working on Mac and later Linux, we were using GCC, which did have thread-safe static initialization. But since all of our code already had to work around MSVC’s lack of support and deal with this itself, the compiler support in GCC was just dead weight, so we disabled it by specifying -fno-threadsafe-statics. Years later, MSVC grew support, but by then, we had many times more thread-safe statics, and who wanted to go back and remove them all? So we specified /Zc:threadSafeInit- there and retained the previous behavior.

Personally, I’d love to move toward the language standard, turn on compiler support for thread-safe static initialization, and allow it to be used anywhere sensible.

--

Nico Weber

unread,
Nov 24, 2016, 11:50:27 AM11/24/16
to Mark Mentovai, Ilya Sherman, cxx, Pavel Kalinnikov
Part if why we use /Zc:threadSafeInit- is because VS2015 generates a _lot_ if code for each static if you don't pass it, and binary size regressed quite a bit without it (if you blame the gn file passing that flag, you'll find a bug with numbers).

Pavel Kalinnikov

unread,
Nov 25, 2016, 9:54:25 AM11/25/16
to Nico Weber, Mark Mentovai, Ilya Sherman, cxx
Thanks everyone for very elaborate responses!

Scott Graham

unread,
Jan 30, 2017, 3:31:34 PM1/30/17
to Pavel Kalinnikov, Nico Weber, Mark Mentovai, Ilya Sherman, cxx
Hi, I plan to flip us to removing /Zc:threadSafeInit- and -fno-threadsafe-statics, i.e. making static initialization thread safe by default.

This is in service of a particular bug, but adding a bunch of workaround code for that problem at this point seems a bit silly.

If anyone objects, or knows of reasons why this won't work please let me know. I plan to proceed by first making our compile options threadsafe, and then recovering the code size penalty (approximately 54k binary size on Windows), as it of course can't be done in the other order. I believe quite a bit of the size will be recovered by the removal of code in LazyInstance instances, but I don't know if it will be an overall net win/loss.


Scott Graham

unread,
Jan 30, 2017, 3:46:04 PM1/30/17
to Pavel Kalinnikov, Nico Weber, Mark Mentovai, Ilya Sherman, cxx

Dmitry Skiba

unread,
Jan 30, 2017, 3:47:12 PM1/30/17
to Scott Graham, Pavel Kalinnikov, Nico Weber, Mark Mentovai, Ilya Sherman, cxx
So, the situation with GCC/clang is the same? I.e. they create dedicated 'state' static and write it before writing the data?

Mark Mentovai

unread,
Jan 30, 2017, 4:17:56 PM1/30/17
to Dmitry Skiba, Ilya Sherman, Pavel Kalinnikov, cxx, Scott Graham, Nico Weber
We have suppressed this feature of GCC and clang by specifying -fno-threadsafe-statics for compatibility with old MSVC, but yes, both GCC and clang have supported thread-safe static initialization for a very long time. Far longer than C++ has required it, in fact.

Nico Weber

unread,
Jan 30, 2017, 6:37:49 PM1/30/17
to Scott Graham, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman, cxx
Sounds great. Thanks, Scott!

Bruce

unread,
Jan 31, 2017, 1:33:49 PM1/31/17
to cxx, sco...@chromium.org, pkali...@google.com, ma...@chromium.org, ishe...@google.com
Yep, sounds great. Go for it. I'm sure that most of the binary size regression can indeed be recovered, and what remains will be the reasonable price to pay for having local statics behave sanely.

Dmitry Skiba

unread,
Jan 31, 2017, 1:39:28 PM1/31/17
to Bruce, cxx, Scott Graham, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
Once this is done, will we update our coding guide? Relying on thread-safe statics can simplify things in some cases.

Scott Graham

unread,
Jan 31, 2017, 1:46:19 PM1/31/17
to Dmitry Skiba, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
Yes, I'll update the style guide. The change to flip behaviour has landed, and I'm looking at simplifying some LazyInstance<T> usage now.

(If anyone feels enthused to simplify code in some subtree, please feel encouraged, and mention what you're attacking at crbug.com/686866.)

Yuri Wiitala

unread,
Jan 31, 2017, 2:52:14 PM1/31/17
to Scott Graham, Dmitry Skiba, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
Can someone clarify: Is the goal to remove the use of LazyInstance where thread-safe static locals can now be used and would be simpler? Or, are we trying to remove *all* uses of LazyInstance everywhere? Or, something else?


Scott Graham

unread,
Jan 31, 2017, 3:15:09 PM1/31/17
to Yuri Wiitala, Dmitry Skiba, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
I believe we should:
- try to not use LazyInstance in new code;
- replace code that uses LazyInstance where it could be replaced by less code (this seems to apply especially to LazyInstance::Leaky);
- maintain LazyInstance in more complex cases where it adds some value.

Moving away from LazyInstance is not urgent, and should just be considered a low-priority clean up and simplification task, perhaps something to do when you notice it in a file you're working in. When doing so, I think it's also valuable to (re-)consider whether a non-leaky LazyInstance could really have been Leaky.



Dale Curtis

unread,
Jan 31, 2017, 3:52:07 PM1/31/17
to Scott Graham, Yuri Wiitala, Dmitry Skiba, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
After converting all of the */media/ targets, I didn't find a single case where continuing to use LazyInstance made sense. They are all fairly easy conversions to the form of GetXXX() where that method has an internal static. The biggest win in our case was simplifying code of the pattern "initialize&&store bool" type classes into a internal function with a static bool.


Dmitry Skiba

unread,
Jan 31, 2017, 3:57:07 PM1/31/17
to Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
BTW, what does our code style say of

Foo* GetFoo() {
  static Foo* foo = new Foo();
  return foo;
}

vs

Foo& GetFoo() {
  static Foo* foo = new Foo();
  return *foo;
}

?

dan...@chromium.org

unread,
Jan 31, 2017, 4:00:04 PM1/31/17
to Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
On Tue, Jan 31, 2017 at 3:57 PM, 'Dmitry Skiba' via cxx <c...@chromium.org> wrote:
BTW, what does our code style say of

Foo* GetFoo() {
  static Foo* foo = new Foo();
  return foo;
}

vs

Foo& GetFoo() {
  static Foo* foo = new Foo();
  return *foo;
}

?

AFAIK it does not say anything and doesn't give preference to returning pointers vs references.
 

Peter Kasting

unread,
Jan 31, 2017, 4:04:19 PM1/31/17
to Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
On Tue, Jan 31, 2017 at 12:57 PM, 'Dmitry Skiba' via cxx <c...@chromium.org> wrote:
BTW, what does our code style say of

Foo* GetFoo() {
  static Foo* foo = new Foo();
  return foo;
}

vs

Foo& GetFoo() {
  static Foo* foo = new Foo();
  return *foo;
}


"it is a very strong convention in Google code that input arguments are values or const references while output arguments are pointers"

The rest of that section is slightly ambiguous, because it speaks strongly of disallowing non-const refs as parameters, but it mostly sounds like it's speaking about input parameters, except for this sentence that speaks about "output arguments".

However, at the least, I think this suggests preferring return-by-pointer, even if it's not mandated.  In most non-Blink Chromium code I've used (with a few high-profile exceptions), we avoid using non-const refs pretty much anywhere.  Because of these factors, I ask authors to avoid non-const refs, and convert code not to use them when I encounter it.

PK

dan...@chromium.org

unread,
Jan 31, 2017, 4:08:51 PM1/31/17
to Peter Kasting, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
Interesting, I've never thought that rules about arguments could apply to return values. Is this a practice followed in google3?

The reasoning for not passing arguments by non-const ref is that the caller can't tell that their lvalue thing is going to be modified. This isn't something relevant for returns though.
 

PK

--
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.

Peter Kasting

unread,
Jan 31, 2017, 4:11:36 PM1/31/17
to Dana Jansens, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
On Tue, Jan 31, 2017 at 1:08 PM, <dan...@chromium.org> wrote:
On Tue, Jan 31, 2017 at 4:04 PM, 'Peter Kasting' via cxx <c...@chromium.org> wrote:
On Tue, Jan 31, 2017 at 12:57 PM, 'Dmitry Skiba' via cxx <c...@chromium.org> wrote:
BTW, what does our code style say of

Foo* GetFoo() {
  static Foo* foo = new Foo();
  return foo;
}

vs

Foo& GetFoo() {
  static Foo* foo = new Foo();
  return *foo;
}


"it is a very strong convention in Google code that input arguments are values or const references while output arguments are pointers"

The rest of that section is slightly ambiguous, because it speaks strongly of disallowing non-const refs as parameters, but it mostly sounds like it's speaking about input parameters, except for this sentence that speaks about "output arguments".

However, at the least, I think this suggests preferring return-by-pointer, even if it's not mandated.  In most non-Blink Chromium code I've used (with a few high-profile exceptions), we avoid using non-const refs pretty much anywhere.  Because of these factors, I ask authors to avoid non-const refs, and convert code not to use them when I encounter it.

Interesting, I've never thought that rules about arguments could apply to return values. Is this a practice followed in google3?

I don't work in google3, so the quote about "output arguments are pointers" being a "strong convention in Google code" is the only information I have.

The reasoning for not passing arguments by non-const ref is that the caller can't tell that their lvalue thing is going to be modified. This isn't something relevant for returns though.

Guessing at motivations, I would say that use of non-const refs in general (not just in function calls) leads to code where it's harder to see that object modifications are happening, so the idea is just to discourage all use of non-const refs.

PK 

dan...@chromium.org

unread,
Jan 31, 2017, 4:17:44 PM1/31/17
to Peter Kasting, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
On Tue, Jan 31, 2017 at 4:11 PM, Peter Kasting <pkas...@google.com> wrote:
On Tue, Jan 31, 2017 at 1:08 PM, <dan...@chromium.org> wrote:
On Tue, Jan 31, 2017 at 4:04 PM, 'Peter Kasting' via cxx <c...@chromium.org> wrote:
On Tue, Jan 31, 2017 at 12:57 PM, 'Dmitry Skiba' via cxx <c...@chromium.org> wrote:
BTW, what does our code style say of

Foo* GetFoo() {
  static Foo* foo = new Foo();
  return foo;
}

vs

Foo& GetFoo() {
  static Foo* foo = new Foo();
  return *foo;
}


"it is a very strong convention in Google code that input arguments are values or const references while output arguments are pointers"

The rest of that section is slightly ambiguous, because it speaks strongly of disallowing non-const refs as parameters, but it mostly sounds like it's speaking about input parameters, except for this sentence that speaks about "output arguments".

However, at the least, I think this suggests preferring return-by-pointer, even if it's not mandated.  In most non-Blink Chromium code I've used (with a few high-profile exceptions), we avoid using non-const refs pretty much anywhere.  Because of these factors, I ask authors to avoid non-const refs, and convert code not to use them when I encounter it.

Interesting, I've never thought that rules about arguments could apply to return values. Is this a practice followed in google3?

I don't work in google3, so the quote about "output arguments are pointers" being a "strong convention in Google code" is the only information I have.

But output arguments != return values. Output arguments are arguments that the function modifies.

A query for "^\ *[a-zA-Z0-9:]+& -operator" finds almost a million instances, so I don't think this is supposed to apply to return values.
 

The reasoning for not passing arguments by non-const ref is that the caller can't tell that their lvalue thing is going to be modified. This isn't something relevant for returns though.

Guessing at motivations, I would say that use of non-const refs in general (not just in function calls) leads to code where it's harder to see that object modifications are happening, so the idea is just to discourage all use of non-const refs.

Calling methods on a non-const-object instead of a non-const-pointer does not seem more ambiguous.

Peter Kasting

unread,
Jan 31, 2017, 4:24:19 PM1/31/17
to Dana Jansens, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
On Tue, Jan 31, 2017 at 1:17 PM, <dan...@chromium.org> wrote:
On Tue, Jan 31, 2017 at 4:11 PM, Peter Kasting <pkas...@google.com> wrote:
On Tue, Jan 31, 2017 at 1:08 PM, <dan...@chromium.org> wrote:
On Tue, Jan 31, 2017 at 4:04 PM, 'Peter Kasting' via cxx <c...@chromium.org> wrote:
On Tue, Jan 31, 2017 at 12:57 PM, 'Dmitry Skiba' via cxx <c...@chromium.org> wrote:
BTW, what does our code style say of

Foo* GetFoo() {
  static Foo* foo = new Foo();
  return foo;
}

vs

Foo& GetFoo() {
  static Foo* foo = new Foo();
  return *foo;
}


"it is a very strong convention in Google code that input arguments are values or const references while output arguments are pointers"

The rest of that section is slightly ambiguous, because it speaks strongly of disallowing non-const refs as parameters, but it mostly sounds like it's speaking about input parameters, except for this sentence that speaks about "output arguments".

However, at the least, I think this suggests preferring return-by-pointer, even if it's not mandated.  In most non-Blink Chromium code I've used (with a few high-profile exceptions), we avoid using non-const refs pretty much anywhere.  Because of these factors, I ask authors to avoid non-const refs, and convert code not to use them when I encounter it.

Interesting, I've never thought that rules about arguments could apply to return values. Is this a practice followed in google3?

I don't work in google3, so the quote about "output arguments are pointers" being a "strong convention in Google code" is the only information I have.

But output arguments != return values. Output arguments are arguments that the function modifies.

Oh, is that what they meant by that phrasing?  That would indeed make sense... I feel silly for misreading it all this time.

A query for "^\ *[a-zA-Z0-9:]+& -operator" finds almost a million instances,

In google3, I assume :).  I see about 2100 instances in Chrome (not counting V8 or third_party), which ranks as "uncommon but not entirely unheard of" for our size.
 
so I don't think this is supposed to apply to return values.

Yes, I agree.

Hmm.  This suggests I should be less hostile to non-const refs in code I encounter.

PK

Brett Wilson

unread,
Jan 31, 2017, 4:28:49 PM1/31/17
to Scott Graham, Yuri Wiitala, Dmitry Skiba, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
On Tue, Jan 31, 2017 at 12:15 PM, Scott Graham <sco...@chromium.org> wrote:
I believe we should:
- try to not use LazyInstance in new code;
- replace code that uses LazyInstance where it could be replaced by less code (this seems to apply especially to LazyInstance::Leaky);

Doesn't a static call a destructor on shutdown? Was this discussed and I missed it? It doesn't seem like we want to add these static destructors.

Brett


Peter Kasting

unread,
Jan 31, 2017, 4:29:42 PM1/31/17
to Brett Wilson, Scott Graham, Yuri Wiitala, Dmitry Skiba, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
On Tue, Jan 31, 2017 at 1:28 PM, Brett Wilson <bre...@chromium.org> wrote:
On Tue, Jan 31, 2017 at 12:15 PM, Scott Graham <sco...@chromium.org> wrote:
I believe we should:
- try to not use LazyInstance in new code;
- replace code that uses LazyInstance where it could be replaced by less code (this seems to apply especially to LazyInstance::Leaky);

Doesn't a static call a destructor on shutdown?

Not with CR_DEFINE_STATIC_LOCAL.

PK

Scott Graham

unread,
Jan 31, 2017, 4:33:55 PM1/31/17
to Brett Wilson, Yuri Wiitala, Dmitry Skiba, Bruce, cxx, Pavel Kalinnikov, Mark Mentovai, Ilya Sherman
On Tue, Jan 31, 2017 at 1:28 PM, Brett Wilson <bre...@chromium.org> wrote:
Yes, a regular object would by default. All LazyInstances are pointers already, so I was implicitly thinking of static raw pointers, not just any old static. AFAIK, there shouldn't be any startup or shutdown code in that case.
 

Brett


--
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.

Mark Mentovai

unread,
Jan 31, 2017, 4:37:26 PM1/31/17
to Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman
After converting and looking at a few of these, I’ve found that the pointer variant has felt like a more natural fit in the majority of situations. The reference version was handy in a few instances where the existing code needed a reference anyway, and it made more sense to convert from pointer to reference centrally in the helper function instead of at each use site. I don’t think that we should express any preference.

Mark Mentovai

unread,
Jan 31, 2017, 4:40:59 PM1/31/17
to Brett Wilson, Scott Graham, Yuri Wiitala, Dmitry Skiba, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman
We’re not doing

Snooze* GetSnooze() {
  static Snooze s;
  return &s;
}

We’re doing

Snooze* GetSnooze() {
  static Snooze* s = new Snooze();
  return s;
}

Nothing registers any at-exit code in this case.

Brett Wilson

unread,
Jan 31, 2017, 4:41:29 PM1/31/17
to Mark Mentovai, Scott Graham, Yuri Wiitala, Dmitry Skiba, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman
On Tue, Jan 31, 2017 at 1:40 PM, Mark Mentovai <ma...@chromium.org> wrote:
We’re not doing

Snooze* GetSnooze() {
  static Snooze s;
  return &s;
}

We’re doing

Snooze* GetSnooze() {
  static Snooze* s = new Snooze();
  return s;
}

Nothing registers any at-exit code in this case.

Ah, sounds good to me.

Brett

Yuzhu Shen

unread,
Jan 31, 2017, 5:09:08 PM1/31/17
to Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman
Returning a reference is nice in the case whether the object is never null:

  Foo& foo();
v.s.
  // Hey users. The return pointer is never null. So you don't need to do null-check.
  Foo* foo();

Yuzhu Shen

unread,
Jan 31, 2017, 5:09:41 PM1/31/17
to Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman
On Tue, Jan 31, 2017 at 2:08 PM, Yuzhu Shen <yzs...@chromium.org> wrote:
Returning a reference is nice in the case whether the object is never null:

"whether" -> "where"

Greg Thompson

unread,
Feb 1, 2017, 4:28:29 AM2/1/17
to Yuzhu Shen, Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman
On Tue, Jan 31, 2017 at 11:09 PM Yuzhu Shen <yzs...@chromium.org> wrote:
Returning a reference is nice in the case whether the object is never null:

  Foo& foo();
v.s.
  // Hey users. The return pointer is never null. So you don't need to do null-check.
  Foo* foo();

This has been my reason for preferring return by non-const reference. Otherwise, it's understandable for someone to DCHECK the return value, which I would say is an anti-pattern as it clutters up the points of use. If these functions ever return nullptr, the house is on fire and a DCHECK isn't going to put it out.

Sidney San Martín

unread,
Feb 1, 2017, 11:47:55 AM2/1/17
to Yuzhu Shen, Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman
On Tue, Jan 31, 2017 at 5:08 PM, Yuzhu Shen <yzs...@chromium.org> wrote:
Returning a reference is nice in the case where the object is never null:

  Foo& foo();
v.s.
  // Hey users. The return pointer is never null. So you don't need to do null-check.
  Foo* foo();

+1. I'm in the middle of removing the possibility of nulls from some code right now, and changing functions to return references (const, in my case) has helped me find a bunch of now-obsolete null checks.
 

Anthony Berent

unread,
Feb 2, 2017, 4:47:25 AM2/2/17
to Sidney San Martín, Yuzhu Shen, Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman
I have always worried about code that assumes that refs can't be null. The following is, in my understanding, entirely legal:

#include <stdio.h>

int &test() {
    int* j=nullptr;
    return *j;
}
int main() {
    int& i = test();
    printf("&i = %p\n", &i);
}

On compiling and running it it prints:

&i = (nil)

Yes, it is a very good convention to say that we will never return null through a reference; but please remember that it is only a convention, and is not enforced by the language.


Tomasz Śniatowski

unread,
Feb 2, 2017, 5:07:18 AM2/2/17
to Anthony Berent, Sidney San Martín, Yuzhu Shen, Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman
That'd be illegal / UB, as defined by the language (and as caught by -fsanitize=undefined).

8.3.2/5: "[...] A reference shall be initialized to refer to a valid object or function. [ Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by indirection through a null pointer, which causes undefined behavior [...]"

clang: "runtime error: reference binding to null pointer of type 'int'"



--
Tomasz Śniatowski

Sylvain Defresne

unread,
Feb 2, 2017, 5:09:32 AM2/2/17
to Anthony Berent, Sidney San Martín, Yuzhu Shen, Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman
AFAICT, the snippet you've posted is Undefined Behaviour according to the standard as it requires dereferencing a null pointer to create the null reference.

There shall be no references to references, no arrays of references, and no pointers to references. The
declaration of a reference shall contain an initializer (8.5.3) except when the declaration contains an explicit
extern specifier (7.1.1), is a class member (9.2) declaration within a class definition, or is the declaration
of a parameter or a return type (8.3.5); see 3.1. A reference shall be initialized to refer to a valid object or
function. [ Note: in particular, a null reference cannot exist in a well-defined program, because the only way
to create such a reference would be to bind it to the “object” obtained by indirection through a null pointer,
which causes undefined behavior. As described in 9.6, a reference cannot be bound directly to a bit-field.
— end note ]

-- Sylvain 

On Thu, Feb 2, 2017 at 10:47 AM, Anthony Berent <abe...@chromium.org> wrote:

Anthony Berent

unread,
Feb 2, 2017, 5:31:37 AM2/2/17
to Sylvain Defresne, Sidney San Martín, Yuzhu Shen, Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman, tsnia...@opera.com
Yes, on further reading, I agree this is undefined. gcc and (oddly in view of  tsniatowski@ comment) the copy of clang I have accept it. While compilers could easily detect this simple case it would clearly be possible to create more complex cases that could not be detected by compilers. As such we are still relying on people obeying coding conventions, rather than any compiler checks, when we say that references cannot be null.

Sidney San Martín

unread,
Feb 2, 2017, 3:20:03 PM2/2/17
to Anthony Berent, Sylvain Defresne, Yuzhu Shen, Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman, tsnia...@opera.com
From my point of view, the difference is that the receiver isn't expected to check if a reference is null. It's a contract, just like the contract that a non-null pointer will, except in special cases, point at valid memory with valid content, even though the compiler can't enforce that.

Yuta Kitamura

unread,
Feb 6, 2017, 12:28:40 AM2/6/17
to Anthony Berent, Sylvain Defresne, Sidney San Martín, Yuzhu Shen, Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, cxx, Pavel Kalinnikov, Ilya Sherman, tsnia...@opera.com
UB has nothing to do with whether compilers accept those code (if some code should be denied by compilers, we call it ill-formed). Compilers are allowed to accept UB code.

We sometimes intentionally write UB code, for example, to trigger a crash, like below:

#if defined(COMPILER_GCC) || defined(__clang__)
#define IMMEDIATE_CRASH() __builtin_trap()
#else
#define IMMEDIATE_CRASH() ((void)(*(volatile char*)0 = 0))
#endif

We usually expect compilers to accept those code, so, if compilers started to reject those simple UB situations, a lot of legitimate UB code (like above) would get rejected, too.

Pavel Kalinnikov

unread,
Feb 14, 2017, 5:17:19 AM2/14/17
to cxx, Anthony Berent, Sylvain Defresne, Sidney San Martín, Yuzhu Shen, Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, Ilya Sherman, tsnia...@opera.com, Yuta Kitamura, Alexei Svitkine
Hello folks,

I can't stand noticing that half of this thread has nothing to deal with its topic :)

Getting back to relevant notes, do we have any macro/whatever to statically assert that static locals are initialized thread-safely?

Now that much code starts assuming thread-safeness of statics, what is the policy regarding changing the code in "base/", e.g. UMA histograms code? Are there any builds with -fno-threadsafe-statics flag, which depend on those? I couldn't find any in codesearch, except for couple of gyp files and generators.

Thank you,
Pavel

Daniel Cheng

unread,
Feb 14, 2017, 5:22:53 AM2/14/17
to Pavel Kalinnikov, cxx, Anthony Berent, Sylvain Defresne, Sidney San Martín, Yuzhu Shen, Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, Ilya Sherman, tsnia...@opera.com, Yuta Kitamura, Alexei Svitkine
I know there have been at least a few CLs changing LazyInstance to a function-local static (such as https://codereview.chromium.org/2667513003, https://codereview.chromium.org/2667993003, and https://codereview.chromium.org/2668813002) so feel free to send CLs for changes like this (perhaps this will help us make the switch to leaky-by-default LazyInstance =)

Daniel

Primiano Tucci

unread,
Feb 14, 2017, 6:54:31 AM2/14/17
to Daniel Cheng, Pavel Kalinnikov, cxx, Anthony Berent, Sylvain Defresne, Sidney San Martín, Yuzhu Shen, Mark Mentovai, Dmitry Skiba, Dale Curtis, Scott Graham, Yuri Wiitala, Bruce, Ilya Sherman, tsnia...@opera.com, Yuta Kitamura, Alexei Svitkine
See discussion in https://groups.google.com/a/chromium.org/d/msg/chromium-dev/3yMRhQvMcLE/OQTVuv9jAAAJ.
My understanding form mark's comment there is that switching to MSVC15 was the last missing bit, which happened a while ago.

Nico Weber

unread,
Feb 14, 2017, 6:58:37 AM2/14/17