Search code examples
cpointersvolatile

Volatile pointer points to non volatile data


I understand that the declaration

int *volatile ptr;

means that the pointer itself is volatile

int a=10;
int *volatile ptr=&a;

Now both ptr and a are being updated. Will it cause any potential problems like old value of a being returned when accessing ptr?

To clarify the use case of volatile pointer in my scenario:

  1. To communicate from interrupt context to task context I am passing addresses to circular queue (which is array of pointers) which will be accessed from task context.
  2. The pointers in this queue are declared volatile.
  3. At index x in queue ,pointer y is present which points to variable a.
  4. Now if I write new pointer to queue (example pointer z which points to variable b) at index x in interrupt context.
  5. When I read index x in task context, since queue is declared as volatile, the pointers will not be optimised.

My doubt is since what the pointer is pointing to is not volatile is there a chance that compiler has optimized for index x and on deferencing pointer at index x it will point to variable a instead of variable b


Solution

  • int* volatile only means that the pointer itself is volatile. The pointed-at data is not volatile-qualified, meaning that the following scenario may cause optimizer bugs:

    int a=10;
    int* volatile ptr=&a;
    
    int main()
    {
      for(;;)
      {
        printf("%d\n", *ptr);
      }
    }
    
    void some_ISR (void)
    {
      a = something;
    }
    

    The compiler is careful not to assume that ptr does not point at the same address every lap in the loop, but apart from that it is free to assume: "aha, after reading ptr it is still pointing at a I see. It has not been updated and I know it is 10". In theory the compiler is free to generate machine code such as this pseudo:

    val = *ptr
    
    forever
    {
      ptr = (update it by reading from memory)
      if ptr != previous
        val =*ptr
    
      print val        
      previous = ptr
    }
    

    Such optimizations may make sense if the compiler can keep the previous value stashed away in a CPU register etc. Suppose it can get rid of a lot of the printf overhead this way, that would be a major optimization.

    So, no this does not give you protection against incorrect optimizations. To achieve that, use volatile int* instead. Or if the pointers themselves may also change, volatile int* volatile.


    To communicate from interrupt context to task context I am passing addresses to circular queue (which is array of pointers) which will be accessed from task context.

    That only makes sense if the pointer itself is changed to point elsewhere by the interrupt. Again, it doesn't mean that the pointed-at data will be updated. But as you write "The pointers in this queue are declared volatile.", you are good, assuming this means that the pointers are volatile* type and not type*volatile.

    Unrelated to this whole issue, you also need a protection against non-atomic access of shared variables. volatile does not give that.