1

Given these definitions:

typedef void foo_t(void);
static void foo(void) {
}

The following, as expected, does not get optimized away: The pointer is read and the function is indirectly (tail) called:

foo_t volatile *gfoo = foo;
void gtest() {
    gfoo();
}

However, if the pointer is declared static, the read and the function call get completely optimized away:

static foo_t volatile *sfoo = foo;
void stest() {
    sfoo();
}

both examples on godbolt

I realize that due to the static definition, the compiler can see that sfoo is never written and hence it wants to assume that it always points to the same empty function, which it will inline given the chance. However, my understanding of volatile is that it should force the read access and not assume anything about the data that is read.

For example, in N1256, the final C99 draft, “6.7.3 Type qualifiers”, it is stated:

An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. […]

The related question When can a volatile variable be optimized away completely? and its answers quote the same paragraph, but as the variable in question is read and not just initialized, I think it agrees that sfoo should not be optimized away.

In case it matters, I read about this in this german blog article about the way openssl tries to use this method to prevent optimizing away dead stores.

wrtlprnft
  • 128
  • 1
  • 4

1 Answers1

7

The way you spelled it, volatile applies to the pointed-to object. If you replace the declarations to ... *volatile ... (instead of ... volatile *...), both examples work as expected (see on godbolt).

(To clarify, const and volatile modifiers can be placed in three positions: const foo *bar, foo const *bar and foo *const bar. The first two mean the same thing - that the pointer bar points to an object of type const foo. The third is the only way to specify that bar is a pointer with a modifier itself)

abel1502
  • 955
  • 4
  • 14