Can an indirect change to const volatility be considered undefined behavior?

Does volatile write to volatile const help introduce undefined behavior? What if I write while I work?

volatile const int x = 42;
const volatile int *p = &x;
*(volatile int *)p = 8; // Does this line introduce undefined behavior?
*(int *)p = 16; // And what about this one?

      

Composite code

+3


source to share


2 answers


This behavior is undefined (for both operators) when trying to change the "initial" const

object. From C11 (N1570) 6.7.3 / p6 Typical classifiers (emphasis):

If an attempt is made to modify an object defined with a const-qual type using an lvalue with a non-const-qualified type , the behavior is undefined.

For the sake of completeness, it may be added that the Standard also states that:

If an attempt is made to access an object defined with a volatile-qualified type using an lvalue with a non-volatile type , the behavior is undefined.



Hence the last statement, that is:

*(int *)p = 16;

      

- undefined for the second phrase (this is "double UB").

I believe the rules are the same for C ++, but don't have a copy of C ++ 14 to confirm.

+8


source


Writing to a variable is initially const

undefined behavior, so all your examples are written to *p

: undefined.

Deletion volatile

by itself is not undefined in and of itself.

However, if we have something like const volatile int *p = (const volatile int*)0x12340000; /* Address of hw register */

that, then deleting volatile

may cause the hardware to update the register value, but your program won't pick it up. (For example, if we "wait" with while(*p & 0x01) ;

, the compiler must reload the value it points to p

every time, but the while((*(const int *)p) & 1) ;

compiler is completely free to read the values ​​and reuses the initial value for the loop forever if bit 0 is set).

You could, of course, have extern volatie int x;

and then use const volatile int *p = &x;

in some code, and x

updated with some other code outside of your current translation unit (like another thread) - in which case deletion is const

either volatile

valid, but as stated above, you can "skip" updated values ​​because the compiler does not expect the global value to update outside of your module unless you call functions.
[Edit, no, disabling volatile

by casting a value is also prohibited in the standard - however, you really need to add const

or volatile

to something and then remove it again if it refers to the original object to not have it].



Edti2: volatile

you need to tell the compiler that "the value can change at any time, even if you think nothing should have changed it." This happens, in general, in two situations:

  • Hardware registers that are updated outside of software in general - for example, status registers for a serial port, a timer counter register, or an interrupt controller interrupt state to name a few cases - there are thousands of other options, but it's still the same idea: the hardware changes the value , without direct relation to the software that accesses such registers.
  • The variable is updated by another thread in the process (or, in the case of shared memory, by another process) - again, the compiler will not be able to "see" such changes. It is often possible to write code that appears to function correctly, by calling a function inside wait loops, etc., and the compiler will still reload the values ​​of non-local variables, but after a while the compiler decides to inline the function call and then realizes that the code is not updating it is a value, so it does not reload the value β†’ error when you check for an "updated" value and find the same old value that was previously loaded by the compiler.

Note also that it is volatile

NOT a guarantee for any thread / process correctness - it just ensures that the compiler does not skip reading or writing to this variable. The programmer doesn't care to make sure, for example, that multiple ordering-dependent values ​​are indeed updated in the correct order, and on systems where caches are not consistent between processing units, that caches become coherent by software [for example, processor and the GPU might not use coherent memory updates, so writes by the CPU don't make it to the GPU until the cache is cleared from the CPU - no amount of applying volatile

to code will fix this]

+5


source







All Articles