(related to this question Is It Safe to Cast Away volatile?, but not quite the same, as that question relates to a specific instance)
Is there ever a case where casting away volatile is not considered a dangerous practice?
(one particular example: if there is a function declared
void foo(long *pl);
and I have to implement
void bar(volatile long *pl);
with part of my implementation requiring bar() to call foo(pl), then it seems like I can't get this to work as is, because the assumptions made by the compilation of foo() and the compilation of the caller of bar() are incompatible.)
As a corollary, if I have a volatile variable v, and I want to call foo(&v) with someone else's function void foo(long *pl), and that person tells me it's safe, I can just cast the pointer before the call, my instinct is to tell them they're wrong because there's no way to guarantee that, and that they should change the declaration to void foo(volatile long *pl) if they want to support the use of volatile variables. Which one of us is correct?
If the variable is declared volatile then it is undefined behaviour to cast away the volatile, just as it is undefined behaviour to cast away the const from a variable declared const. See Annex J.2 of the C Standard:
The behavior is undefined in the following circumstances:
...
— An attempt is made to modify an object defined with a const-qualified type through
use of an lvalue with non-const-qualified type (6.7.3).
— An attempt is made to refer to an object defined with a volatile-qualified type through
use of an lvalue with non-volatile-qualified type (6.7.3).
If, however, you just have a volatile pointer or a volatile reference to a non-volatile variable then you can freely cast away volatile.
volatile int i=0;
int j=0;
volatile int* pvi=&i; // ok
volatile int* pvj=&j; // ok can take a volatile pointer to a non-volatile object
int* pi=const_cast<int*>(pvi); // Danger Will Robinson! casting away true volatile
int* pj=const_cast<volatile int*>(pvj); // OK
*pi=3; // undefined behaviour, non-volatile access to volatile variable
*pj=3; // OK, j is not volatile
Casting away volatile would be ok, once the value is in fact no longer volatile. In SMP/multi-threading situations, this could become true after acquiring a lock (and passing a memory barrier, which is most often implicit in acquiring the lock).
So a typical pattern for this would be
volatile long *pl = /*...*/;
//
{
Lock scope(m_BigLock); /// acquire lock
long *p1nv = const_cast<long *>(p1);
// do work
} // release lock and forget about p1nv!
But I could come up with a number of other scenarios in which values stop being volatile. I won't suggest them here, as I'm sure you can come up with them yourself, if you know what you're doing. Otherwise, the locking scenarios seems solid enough to provide as an example
With a signature of foo(long *pl), the programmer is declaring that they are not expecting the pointed-to long value to change externally during the execution of foo. Passing a pointer to a long value that is being concurrently modified throughout an invocation might even lead to erroneous behavior if the compiler emits code that dereferences the pointer multiple times due to lack of registers and by it choosing not to store the value of the first dereference on the stack. For example, in:
void foo(long *pl) {
char *buf = (char *) malloc((size_t) *pl);
// ... busy work ...
// Now zero out buf:
long l;
for (l = 0; l < *pl; ++l) {
buf[l] = 0;
}
free(buf);
}
foo could overrun the buffer in the "zero out buf" step if the long value is increased while the busy work is being performed.
If the foo() function is supposed to atomically increment the long value pointed to by pl, then it would be incorrect for the function to take long *pl and not volatile long *pl because the function clearly requires that accesses of the long value be a sequence point. If foo() only atomically incremented, the function might work, but it would not be correct.
Two solutions to this problem have already been suggested in comments:
Wrap foo taking long * in an overload taking volatile long *:
inline void foo(volatile long *pvl) {
long l = *pvl;
foo(&l);
*pvl = l;
}
Change the declaration of foo to void foo(volatile long *pvl).
Related
AFAIK removing constness from const variables is undefined behavior:
const int i = 13;
const_cast<int&>(i) = 42; //UB
std::cout << i << std::endl; //out: 13
But are const function arguments "real" constants? Let's consider following example:
void foo(const int k){
const_cast<int&>(k) = 42; //UB?
std::cout << k << std::endl;
}
int main(){
foo(13); //out: 42
}
Seems like compiler doesn't apply the same optimizations to const int k as to const int i.
Is there UB in the second example? Does const int k help compiler to optimize code or compiler just checks const correctness and nothing more?
Example
The i in const int i = 13; can be used as constant expression (as template argument or case label) and attempts to modify it are undefined behavior. It is so for backwards compatibility with pre-C++11 code that did not have constexpr.
The declarations void foo(const int k); and void foo(int k); are declaring same function; the top level const of parameters does not participate in function's signature. Parameter k must be passed by value and so can't be "real" constant. Casting its constness away is not undefined behavior. Edit: But any attempt to modify it is still undefined because it is const object [basic.type.qualifier] (1.1):
A const object is an object of type const T or a non-mutable subobject of such an object.
By [dcl.type.cv] 4 const object can't be modified:
Except that any class member declared mutable (10.1.1) can be modified, any attempt to modify a const object during its lifetime (6.8) results in undefined behavior.
And since function parameters are with automatic storage duration a new object within its storage can't be also created by [basic.life] 10:
Creating a new object within the storage that a const complete object with static, thread, or automatic storage duration occupies, or within the storage that such a const object used to occupy before its lifetime ended, results in undefined behavior.
It is unclear why k was declared const at the first place if there is plan to cast its constness away? The only purpose of it feels to be to confuse and to obfuscate.
Generally we should favor immutability everywhere since it helps people to reason. Also it may help compilers to optimize. However where we only declare immutability, but do not honor it, there it works opposite and confuses.
Other thing that we should favor are pure functions. These do not depend on or modify any external state and have no side-effects. These also are easier to reason about and to optimize both for people and for compilers. Currently such functions can be declared constexpr. However declaring the by-value parameters as const does not help any optimizations to my knowledge, even in context of constexpr functions.
But are const function arguments "real" constants?
I think the answer is yes.
They won't be stored in ROM (for example), so casting away const will at least appear to work OK. But my reading of the standard is that the the parameter's type is const int and therefore it is a const object ([basic.type.qualifier]), and so modifying it is undefined ([dcl.type.cv]).
You can confirm the parameter's type fairly easily:
static_assert( std::is_same_v<const int, decltype(k)> );
Is there UB in the second example?
Yes, I think there is.
Does const int k help compiler to optimize code or compiler just checks const correctness and nothing more?
In theory the compiler could assume that in the following example k is not changed by the call to g(const int&), because modifying k would be UB:
extern void g(const int&);
void f(const int k)
{
g(k);
return k;
}
But in practice I don't think compilers take advantage of that, instead they assume that k might be modified (compiler explorer demo).
I'm not sure what you mean by a "real" const, but here goes.
Your const int i is a variable declaration outside of any function. Since modifying that variable would cause Undefined Behaviour, the compiler gets to assume that its value will never change. One easy optimization would be that anywhere you read from i, the compiler doesn't have to go and read the value from main memory, it can emit the assembly to use the value directly.
Your const int k (or the more interesting const int & k) is a function parameter. All it promises is that this function won't be changing the value of k. That doesn't mean that it cannot be changed somewhere else. Each invocation of the function could have a different value for k.
Consider the following code:
int square(volatile int *p)
{
return *p * *p;
}
Now, the volatile keyword indicates that the value in a
memory location can be altered in ways unknown to the compiler or have
other unknown side effects (e.g. modification via a signal interrupt,
hardware register, or memory mapped I/O) even though nothing in the
program code modifies the contents.
So what exactly happens when we declare a pointer as volatile?
Will the above mentioned code always work, or is it any different from this:
int square(volatile int *p)
{
int a = *p;
int b = *p
return a*b;
}
Can we end up multiplying different numbers, as pointers are volatile?
Or is there better way to do so?
Can a pointer be volatile?
Absolutely; any type, excluding function and references, may be volatile-qualified.
Note that a volatile pointer is declared T *volatile, not volatile T*, which instead declares a pointer-to-volatile.
A volatile pointer means that the pointer value, that is its address and not the value pointed to by, may have side-effects that are not visible to the compiler when it's accessed; therefore, optimizations deriving from the "as-if rule" may not be taken into account for those accesses.
int square(volatile int *p) { return *p * *p; }
The compiler cannot assume that reading *p fetches the same value, so caching its value in a variable is not allowed. As you say, the result may vary and not be the square of *p.
Concrete example: let's say you have two arrays of ints
int a1 [] = { 1, 2, 3, 4, 5 };
int a2 [] = { 5453, -231, -454123, 7565, -11111 };
and a pointer to one of them
int * /*volatile*/ p = a1;
with some operation on the pointed elements
for (int i = 0; i < sizeof(a1)/sizeof(a1[0]); ++i)
*(p + i) *= 2;
here p has to be read each iteration if you make it volatile because, perhaps, it may actually point to a2 due to external events.
Yes, you can of course have a volatile pointer.
Volatile means none more and none less than that every access on the volatile object (of whatever type) is treated as a visible side-effect, and is therefore exempted from optimization (in particular, this means that accesses may not be reordered or collapsed or optimized out alltogether). That's true for reading or writing a value, for calling member functions, and of course for dereferencing, too.
Note that when the previous paragraph says "reordering", a single thread of execution is assumed. Volatile is no substitute for atomic operations or mutexes/locks.
In more simple words, volatile generally translates to roughly "Don't optimize, just do exactly as I say".
In the context of a pointer, refer to the exemplary usage pattern given by Chris Lattner's well-known "What every programmer needs to know about Undefined Behavior" article (yes, that article is about C, not C++, but the same applies):
If you're using an LLVM-based compiler, you can dereference a "volatile" null pointer to get a crash if that's what you're looking for, since volatile loads and stores are generally not touched by the optimizer.
Yes. int * volatile.
In C++, keywords according to type/pointer/reference go after the token, like int * const is constant pointer to integer, int const * is pointer to constant integer, int const * const is constant pointer to constant integer e.t.c. You can write keyword before the type only if it's for the first token: const int x is equal to int const x.
The volatile keyword is a hint for the compiler (7.1.6.1/7):
Note:
volatile
is a hint to the implementation to avoid aggressive optimization involving the object
because the value of the object might be changed by means undetectable by an implementation. Furthermore,
for some implementations,
volatile
might indicate that special hardware instructions are required to access
the object. See
1.9
for detailed semantics. In general, the semantics of
volatile
are intended to be the
same in C
++
as they are in C.
— end note
]
What does it mean? Well, take a look at this code:
bool condition = false;
while(!condition)
{
...
}
by default, the compiler will easilly optimize the condition out (it doesn't change, so there is no need to check it at every iteration). If you, however, declare the condition as volatile, the optimization will not be made.
So of course you can have a volatile pointer, and it is possible to write code that will crash because of it, but the fact that a variable is volative doesn't mean that it is necessarily going to be changed due to some external interference.
Yes, a pointer can be volatile if the variable that it points to can change unexpectedly even though how this might happen is not evident from the code.
An example is an object that can be modified by something that is external to the controlling thread and that the compiler should not optimize.
The most likely place to use the volatile specifier is in low-level code that deals directly with the hardware and where unexpected changes might occur.
You may be end up multiplying different numbers because it's volatile and could be changed unexpectedly. So, you can try something like this:
int square(volatile int *p)
{
int a = *p;
return a*a;
}
int square(volatile int *p)
{
int a = *p;
int b = *p
return a*b;
}
Since it is possible for the value of *ptr to change unexpectedly, it is possible for a and b to be different. Consequently, this code could return a number that is not a square! The correct way to code this is:
long square(volatile int *p)
{
int a;
a = *p;
return a * a;
}
I know that where possible you should use the const keyword when passing parameters around by reference or by pointer for readability reasons. Is there any optimizations that the compiler can do if I specify that an argument is constant?
There could be a few cases:
Function parameters:
Constant reference:
void foo(const SomeClass& obj)
Constant SomeClass object:
void foo(const SomeClass* pObj)
And constant pointer to SomeClass:
void foo(SomeClass* const pObj)
Variable declarations:
const int i = 1234
Function declarations:
const char* foo()
What kind of compiler optimizations each one offers (if any)?
Source
Case 1:
When you declare a const in your program,
int const x = 2;
Compiler can optimize away this const by not providing storage for this variable; instead it can be added to the symbol table. So a subsequent read just needs indirection into the symbol table rather than instructions to fetch value from memory.
Note: If you do something like:
const int x = 1;
const int* y = &x;
Then this would force compiler to allocate space for x. So, that degree of optimization is not possible for this case.
In terms of function parameters const means that parameter is not modified in the function. As far as I know, there's no substantial performance gain for using const; rather it's a means to ensure correctness.
Case 2:
"Does declaring the parameter and/or the return value as const help the compiler to generate more optimal code?"
const Y& f( const X& x )
{
// ... do something with x and find a Y object ...
return someY;
}
What could the compiler do better? Could it avoid a copy of the parameter or the return value?
No, as argument is already passed by reference.
Could it put a copy of x or someY into read-only memory?
No, as both x and someY live outside its scope and come from and/or are given to the outside world. Even if someY is dynamically allocated on the fly within f() itself, it and its ownership are given up to the caller.
What about possible optimizations of code that appears inside the body of f()? Because of the const, could the compiler somehow improve the code it generates for the body of f()?
Even when you call a const member function, the compiler can't assume that the bits of object x or object someY won't be changed. Further, there are additional problems (unless the compiler performs global optimization): The compiler also may not know for sure that no other code might have a non-const reference that aliases the same object as x and/or someY, and whether any such non-const references to the same object might get used incidentally during the execution of f(); and the compiler may not even know whether the real objects, to which x and someY are merely references, were actually declared const in the first place.
Case 3:
void f( const Z z )
{
// ...
}
Will there be any optimization in this?
Yes because the compiler knows that z truly is a const object, it could perform some useful optimizations even without global analysis. For example, if the body of f() contains a call like g( &z ), the compiler can be sure that the non-mutable parts of z do not change during the call to g().
Before giving any answer, I want to emphasize that the reason to use or not use const really ought to be for program correctness and for clarity for other developers more so than for compiler optimizations; that is, making a parameter const documents that the method will not modify that parameter, and making a member function const documents that that member will not modify the object of which it is a member (at least not in a way that logically changes the output from any other const member function). Doing this, for example, allows developers to avoid making unnecessary copies of objects (because they don't have to worry that the original will be destroyed or modified) or to avoid unnecessary thread synchronization (e.g. by knowing that all threads merely read and do not mutate the object in question).
In terms of optimizations a compiler could make, at least in theory, albeit in an optimization mode that allows it to make certain non-standard assumptions that could break standard C++ code, consider:
for (int i = 0; i < obj.length(); ++i) {
f(obj);
}
Suppose the length function is marked as const but is actually an expensive operation (let's say it actually operates in O(n) time instead of O(1) time). If the function f takes its parameter by const reference, then the compiler could potentially optimize this loop to:
int cached_length = obj.length();
for (int i = 0; i < cached_length; ++i) {
f(obj);
}
... because the fact that the function f does not modify the parameter guarantees that the length function should return the same values each time given that the object has not changed. However, if f is declared to take the parameter by a mutable reference, then length would need to be recomputed on each iteration of the loop, as f could have modified the object in a way to produce a change in the value.
As pointed out in the comments, this is assuming a number of additional caveats and would only be possible when invoking the compiler in a non-standard mode that allows it to make additional assumptions (such as that const methods are strictly a function of their inputs and that optimizations can assume that code will never use const_cast to convert a const reference parameter to a mutable reference).
Function parameters:
const is not significant for referenced memory. It's like tying a hand behind the optimizer's back.
Suppose you call another function (e.g. void bar()) in foo which has no visible definition. The optimizer will have a restriction because it has no way of knowing whether or not bar has modified the function parameter passed to foo (e.g. via access to global memory). Potential to modify memory externally and aliasing introduce significant restrictions for optimizers in this area.
Although you did not ask, const values for function parameters does allow optimizations because the optimizer is guaranteed a const object. Of course, the cost to copy that parameter may be much higher than the optimizer's benefits.
See: http://www.gotw.ca/gotw/081.htm
Variable declarations: const int i = 1234
This depends on where it is declared, when it is created, and the type. This category is largely where const optimizations exist. It is undefined to modify a const object or known constant, so the compiler is allowed to make some optimizations; it assumes you do not invoke undefined behavior and that introduces some guarantees.
const int A(10);
foo(A);
// compiler can assume A's not been modified by foo
Obviously, an optimizer can also identify variables which do not change:
for (int i(0), n(10); i < n; ++i) { // << n is not const
std::cout << i << ' ';
}
Function declarations: const char* foo()
Not significant. The referenced memory may be modified externally. If the referenced variable returned by foo is visible, then an optimizer could make an optimization, but that has nothing to do with the presence/absence of const on the function's return type.
Again, a const value or object is different:
extern const char foo[];
The exact effects of const differ for each context where it is used. If const is used while declaring an variable, it is physically const and potently resides in read-only memory.
const int x = 123;
Trying to cast the const-ness away is undefined behavour:
Even though const_cast may remove constness or volatility from any pointer or reference, using the resulting pointer or reference to write to an object that was declared const or to access an object that was declared volatile invokes undefined behavior. cppreference/const_cast
So in this case, the compiler may assume that the value of x is always 123. This opens some optimization potential (constants propagation)
For functions it's a different matter. Suppose:
void doFancyStuff(const MyObject& o);
our function doFancyStuff may do any of the following things with o.
not modify the object.
cast the constness away, then modify the object
modify an mutable data member of MyObject
Note that if you call our function with an instance of MyObject that was declared as const, you'll invoke undefined behavior with #2.
Guru question: will the following invoke undefined behavior?
const int x = 1;
auto lam = [x]() mutable {const_cast<int&>(x) = 2;};
lam();
SomeClass* const pObj creates a constant object of pointer type. There exists no safe method of changing such an object, so the compiler can, for example, cache it into a register with only one memory read, even if its address is taken.
The others don't enable any optimizations specifically, although the const qualifier on the type will affect overload resolution and possibly result in different and faster functions being selected.
I have fairly decent C++ skills, but this one cast has been giving me issues. I have a function that takes in the following parameters: (volatile void **, void * , void*). I have 3 int* variables and I am trying to pass them in as (&var1, var2, var3). However, I am getting the following error: Cannot convert parameter 1 from int** to volatile void**. Is there a specific cast that needs to be made to allow for this? Below is a snippet of code that I am using. Any help is greatly appreciated.
int* pVal = InterlockedCompareExchangePointer(&cur_val, new_val, old_val);
This is being done in VS2010 on a windows XP machine.
The first one should be volatile void ** and you have int **. You can either just cast to volatile void**, or (better) declare the original variable as volatile and then cast.
volatile means that the variable can be changed elsewhere outside of your code, and basically it means that the variable won't be optimized, but since your original variable is not defined as volatile it might still be optimized, and you would get incorrect results.
You can do a const_cast, but the best thing you can do is to declare your variable a volatile int* (i.e. pointer to volatile int) because otherwise the result might be undefined.
InterlockedCompareExchangePointer does an operation that may be beyond the optimizer's scope to analyze, so it's important that the variable is volatile to make sure its value is fetched from memory (and not cached in registers etc.) each time it is being used.
In addition to declaring the int as volatile, you still need to cast it as:
int* pVal = (int *)InterlockedCompareExchangePointer((void **)&cur_val, (void *)new_val, (void *)old_val);
Note the cast of the value returned from the function too. It returns a void *, so it must be cast to int *.
C++ requires explicit casts.
Most of the time, I am doing this way.
class a {
public:
~ a() {
i = 100; // OK
delete (int *)j; // Compiler happy. But, is it safe?
// The following code will lead compilation error : delete j;
}
private:
volatile int i;
volatile int *j;
};
int main() {
a aa;
}
However, I saw an article here:
https://www.securecoding.cert.org/confluence/display/seccode/EXP32-C.+Do+not+access+a+volatile+object+through+a+non-volatile+reference
Casting away volatile allows access to
an object through a non-volatile
reference. This can result in
undefined and perhaps unintended
program behavior.
So, what will be the workaround for my above code example?
Here is the error message I get if I use
delete j
Note that, this is output from VC6 (Don't ask why I am using VC6!)
c:\projects\a\a.cpp(5) : error C2664:
'delete' : cannot convert parameter 1
from 'volatile int *' to 'void *'
Conversion loses qualifiers
Nothing. If you don't access the volatile memory, the semantics of volatile are unaffected. If you accessed volatile memory through a casted non-volatile pointer, the compiler might optimize the reference away. If the value had changed, you'd have the wrong value. For some value of wrong. ;-)
The delete doesn't access the volatile memory, it just frees it. Sort of an uncommon thing to do with volatile memory.
deleteing a volatile would imply that you've serialized access to it so it is not, in fact, volatile any more. The proper way to remove the volatile (once you know it's safe) is with const_cast<int*>.
If the pointer, and not the int, is volatile, then you really meant int *volatile j. Moreover, if all the members of a class are volatile, you probably want to qualify the entire object at once, a volatile aa;.
It depends on the meaning you expect from your volatile variable. Right now, j is a pointer to a volatile integer; is that what you mean? If so, it's safe since you don't need to access the volatile value, just its address, which isn't volatile.
If, however, you meant that you want a volatile pointer to an integer, the required syntax is int* volatile j. In that case, it could be problematic to cast it to a non-volatile pointer first, but I don't think your compiler would complain if you tried to delete it as is. G++, for one, doesn't.
That should be fine, since you're not accessing the variable after casting away the volatile. However, I don't know why you'd get an error regardless. I tried that code myself, and everything seemed to go fine, what did you see happen?