How to prevent compiler from optimizing a load to variable that is never used

7.7k views Asked by At

Intro: Im trying to quick hack fix old code and use __try MSVC extension to check if some ptr points to some legit memory or if *ptr will cause memory violation(if so I drop processing of this ptr). So I wrote something like:

bool checkIsPtrPointingToValidAddress(const void *ptr)
{
    __try
    {
        auto cpy = *((int*)ptr); // force mem access...
        if ( (cpy ==42) && ((rand()+rand()+rand()+rand()+ rand()) == 1))
        {
            FILE* pFile = fopen ("tempdata.dat","w"); //... by unlikely but possible action
             fputs (" ",pFile);
             fclose (pFile);
        }
        return true;
    }
    __except(1)
    {
        return false;
    }

}

Thing is that my solution to force mem access seems weird, ugly, and as a bonus I'm not sure it is correct. Also please not I can't disable optimizations on the entire project, so that is not an option. And documentation for pragma optimize on MSDN sucks, aka it is not clear if "" disables all optimizations on the function.

3

There are 3 answers

5
Voo On

First of all that's a pretty bad idea to begin with, so you may want to think the whole design over. But if you're forced to stick with it then something like:

volatile auto copy1 = *((char*)ptr);  // using int* here could lead to aliasing violations, so better char in the general case..
volatile auto copy2 = *((char*)ptr);
if (copy1 != copy2) 
   throw std::exception("Cannot happen, but compiler cannot know this");

should certainly do the trick. The compiler can't eliminate the reads or assume that they are identical so has to execute the code. On the other hand assuming no threading problems or other interesting scenarios we know that the two reads will be identical so not cause the exception to be thrown.

Added

By the rules of the standard, any read from or write to a volatile object constitutes observable behaviour (a.k.a. side effect), so even the following should be enough:

volatile auto copy = *((char*)ptr);

This includes a write into the volatile object copy, so it cannot be optimised away.

0
Jan Korous On

From answers to similar questions here at SO it seems that it is:

  • compiler dependent
  • nontrivial

The best source of info I found is question/answers here:

Check if a pointer points to allocated memory on the heap

The most reasonable to me seems:

  1. static analysis (valgrind), debugging, refactoring
  2. use some hack for your compiler
  3. check commercial solution advertised in that answer
0
Strings On

The Windows API has

BOOL WINAPI IsBadReadPtr(_In_ const VOID *lp,_In_ UINT_PTR ucb);
BOOL WINAPI IsBadWritePtr(_In_ LPVOID lp, _In_ UINT_PTR ucb);

You need to read the remarks section, but your case may be simple enough that these functions may suffice. Regardless the remarks section gives some helpful advice when trying to handle unsafe pointers yourself.