3

A follow-up question to this one

We have the following code:

#include <iostream>

struct A 
{
    static int n;
};

int A::n = 5;

int main() 
{
    A* a; //uninitialized on purpose
    std::cout << a->n; //UB?
}

Is such access an Undefined Behaviour? On one side, no object is needed to access static class members, on the other, operator-> on uninitialized pointer is asking for trouble.

Note: GCC and MSVC compiles this code without any warnings, Clang complains about uninitialized usage. https://godbolt.org/z/Gy5fR2

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
  • Similar question [here](https://stackoverflow.com/questions/28482809/c-access-static-members-using-null-pointer) although I am rather doubtful about the top answer – M.M Nov 17 '19 at 22:12
  • I reopened this because the duplicate dealt with null pointers, whereas this question deals with an uninitialized pointer. Since it's not clear whether applying `*` to a null pointer is UB, the questions are different. – Brian Bi Nov 17 '19 at 22:14
  • @M.M It's interesting, because the question that was linked here as duplicate originally (https://stackoverflow.com/questions/3498444/c-static-const-access-through-a-null-pointer?noredirect=1&lq=1) has top answer saying "yes, it's UB" and is closed as duplicate with the one you linked, which says "no, it's not". – Yksisarvinen Nov 17 '19 at 22:16
  • @Yksisarvinen well, I've gone out on a limb and posted an answer to the other question – M.M Nov 17 '19 at 22:36
  • @Brian If deref of null is not UB, how is it defined? Does it refer to an object? To a non object? – curiousguy Nov 18 '19 at 23:39
  • @curiousguy It is unclear. There is an old unresolved issue about this, CWG 232. I think the intent is that the standard will eventually be changed to say that dereferencing a null pointer is ok, but binding the resulting lvalue (an "empty lvalue") to a reference would still cause UB. I think the committee is taking its time with this because they have other priorities. – Brian Bi Nov 18 '19 at 23:43
  • @Brian Why would the committee make that complexifying change? The std would need to list all uses of an empty lvalue to make them illegal. Would &empty` even be allowed? – curiousguy Nov 18 '19 at 23:48
  • @curiousguy I don't know the answer. – Brian Bi Nov 19 '19 at 15:35
  • @Brian "_I think the committee is taking its time with this because they have other priorities._" Probably; but it's bizarre that answer such a basic Q of when a ptr can be dereferenced is not a priority; the C++ committee was never very interested in defining the most basic stuff. They waited more than a decade before they tried to give some possible meaning to the use of a union! (and then, it's a ridiculous attempt where you have to admit that an lvalue refers to a future entity) – curiousguy Nov 21 '19 at 22:02
  • 1
    @curiousguy I agree with you. It's unclear to me why the committee cannot allocate more time to fixing these issues (after all, it has more membership now than ever before). At the very least, I believe this kind of issue should be fixed before further "improvements" are introduced to the memory/object model which introduce even more issues. – Brian Bi Nov 21 '19 at 22:06

1 Answers1

10

The semantics of a->n are that *a is evaluated, but not accessed, since the data member is static. See C++17 [expr.ref]:

... The postfix expression before the dot or arrow is evaluated ... The expression E1->E2 is converted to the equivalent form (*(E1)).E2 ...

There is also a footnote that says:

If the class member access expression is evaluated, the subexpression evaluation happens even if the result is unnecessary to determine the value of the entire postfix expression, for example if the id-expression denotes a static member.

In this case, the expression *a is evaluated. Since a is an automatic variable that has not been initialized, [dcl.init]/12 applies:

If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases: [ ... ]

Evaluating *a clearly requires accessing the value of the pointer variable a, which is an indeterminate value, therefore it is UB.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312