2

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.

NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • 4
    I think that’s what the `volatile` keyword is for. – Holger Sep 06 '13 at 10:54
  • but if it is not used, wont dead code elimination still kill that load... aka it can prove that I dont use it... Or volatile semantics require load to happen ? – NoSenseEtAl Sep 06 '13 at 11:07

3 Answers3

10

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 copy1 = *((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.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
Voo
  • 29,040
  • 11
  • 82
  • 156
  • 1
    A write to a `volatile` memory location is observable behaviour. So simply `volatile auto copy = *((char*)ptr);` is good enough to prevent optimising it out. See `C++11 [intro.execution]§8+§12` – Angew is no longer proud of SO Sep 06 '13 at 11:28
  • @Angew Did you mean `*((char*)ptr) = *((char*)ptr);`? Because otherwise I don't see a write in your example? That should work too, although a write is generally more expensive than a read so not necessarily better. The question is if a read alone is also observable or not. – Voo Sep 06 '13 at 11:44
  • `ptr`, even after the cast is not `volatile`. And you're reading from it. And then *writing* the result of this read into `copy`, which is `volatile`. So this write cannot be optimised away (and, by definition, neither can the previous read of its value). – Angew is no longer proud of SO Sep 06 '13 at 11:46
  • @Angew Ah I see, makes sense that volatile would also apply to non-pointers in the same way (although the ratio behind volatile doesn't). Also obviously a bug in the original even if it still would work. Want to write your own answer with this much better solution or update this one here? I think you deserve the rep there. – Voo Sep 06 '13 at 11:51
  • That blog link is broken. Has it moved, or is an archive link the best way to preserve the answer? – Xevion Jul 12 '23 at 05:15
4

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.

Strings
  • 1,674
  • 10
  • 16
0

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
Community
  • 1
  • 1
Jan Korous
  • 666
  • 4
  • 11