6

As you know, we cannot use memset() for zeroing a memory if it is not accessed later because it may be optimized by compiler. I saw a suggestion in cpp ref that we can use std::fill with a volatile pointer to solve this problem. Now here are my questions:

  1. Does this statement means if the pointer is not volatile, std::fill may be optimized too?
  2. How we can get a volatile pointer to a container, for example vector? Does something like this work?
vector<int> v;
volatile auto ptr = v.data();
Afshin
  • 8,839
  • 1
  • 18
  • 53
  • 1
    If the memory is not accessed, why set it to zeroes anyway? – Devolus Apr 07 '21 at 06:14
  • 6
    @Devolus There are a lot of reasons. A common one is **security**. For example, you need to zero an encryption key when you don't need it anymore to prevent dumping key from memory. – Afshin Apr 07 '21 at 06:15
  • You may consider using a customer memory allocator – prehistoricpenguin Apr 07 '21 at 06:17
  • 1
    https://stackoverflow.com/questions/3785798/does-using-pointer-to-volatile-prevent-compiler-optimizations-at-all-times – David Bien Apr 07 '21 at 06:25
  • @DavidBien Thanks for topic, but it only answers first question and it does not say anything about 2nd part. – Afshin Apr 07 '21 at 06:28
  • Consider using `gsl::ensures` or like something. https://github.com/microsoft/GSL/blob/main/include/gsl/assert#L129 – 김선달 Apr 07 '21 at 06:28
  • https://stackoverflow.com/questions/9935190/why-is-a-point-to-volatile-pointer-like-volatile-int-p-useful and yes, obtaining a volatile pointer to a vector's data should be enough to ensure that that vector is not optimized out - unless of course the method in which you obtain that pointer is somehow optimized out... :-P – David Bien Apr 07 '21 at 06:52
  • *"but it only answers first question"*, that's why it should be one question by question only. – Jarod42 Apr 07 '21 at 09:27
  • 4
    Notice that `volatile auto ptr = v.data();` results in `int* volatile` and not to `int volatile*` (or `volatile int*`). – Jarod42 Apr 07 '21 at 09:33

1 Answers1

3

Yes, this will work:

volatile int* ptr = vec.data();
std::fill(ptr, ptr+vec.size(), 0);

The one thing that prevents the compiler from optimizating it away is the volatile keyword (this is basically the whole purpose of that keyword), so std::fill with a non-volatile pointer will also be optimized.

Since memset is defined to take a non-volatile pointer, it can be optimized away even if you pass a volatile pointer to it (in which case you will also need the -fpermissive flag to allow the compiler to convert the volatile pointer to a non-volatile pointer - otherwise it will not compile).

I made a small example of the possibilities, which makes it quite visible: https://godbolt.org/z/xqYG1Ksod
(Note that I used a raw array instead of a vector, as the vector constructor would otherwise add more unrelated noise to the asm output).

olm
  • 401
  • 2
  • 6
  • 4
    From a comment by Jarod42 above: Notice that `volatile auto ptr = v.data();` results in `int* volatile` and not to `int volatile*` (or `volatile int*`). – interjay Apr 07 '21 at 09:45
  • @interjay: Thanks, I updated the answer (not a big fan of auto anyway, only used it because it was used in the question) – olm Apr 07 '21 at 09:53
  • From linked question, compilers are free to optimize as source is not really `volatile`. – Jarod42 Apr 07 '21 at 13:35