Checking if my const variable has not been modified externally
My question now is if I've declared a constant using const
, I read that it'开发者_如何学编程s possible for it to be modified externally (maybe by a device connected to the system). I want to know if it's possible to check if my constant has been modified or not. Naturally, I would try something like this:
const double PI = 3.1412 //blah blah blah
// ...
if (PI == 3.1412) {
// do something with PI
}
which clearly will not compile since a constant cannot be an lvalue.
How do I go about this? Or is it impossible (I don't want to waste my time if it cannot be done)?
Thanks.
First of all, why won't your example compile? If you couldn't compare constants, they would be kind of useless.
I would classify this as a waste of time. If something external to your program is modifying your memory, then what's to stop it from also modifying the memory you store your comparison at? In your example, that test could fail not because PI
changed, but because 3.1415
did... that number is stored somewhere, after all.
If your program changes the value of PI
, then it is broken, and you can't be sure the test works reliably anyhow. That's firmly undefined behavior, so anything goes. Its a lot like testing if a reference parameter references null... a well defined program can not possibly result in the test failing, and if it could pass you can't be sure the program is in a functioning state anyhow, so the test itself is a waste of time.
In either case, the compiler will probably decide that the test is a waste of time, and remove it all together.
Now, there is one situation that is slightly different from what you originally stated, which might be what your source was refering to. Consider the following code:
void external_function();
void internal_function(const int& i) {
cout << i << "...";
external_function();
cout << i;
}
Within internal_function
, the compiler can not assume that both outputs are identical. i
could be a reference to an integer that is not actually const
, and external_function
could change it. The key difference here is that i
is a reference, whereas in your original question PI
is a constant value.
int pi = 3;
void external_function() { pi = 4; }
void internal_function(const int&);
int main() {
internal_function(pi);
}
That will result in 3...4
being printed. Even though i
is a constant reference, the compiler has to assume it might change because something it can't see might change it.
In that case, such a test might be useful under certain circumstances.
void internal_function(const int& i) {
const int original_i = i;
cout << i << "...";
external_function();
cout << i << endl;
if(i != original_i) cout << "lol wut?" << endl;
}
In this case, the test is useful. original_i
is guarenteed to have not changed [and if it has, see the first half of this answer], and if i
has changed the assertion will fail.
const folding is important here. With your sample code, the
const double PI = 3.1412; //blah blah blah
if (PI == 3.1412) {
}
the literal might actually share the storage space for the constant.
It seems you want to have 'insurance' or 'tamper-detection' of some kind.
For this purpose, you'd have to self-sign the binary with some kind of certificate. However, with sufficient reverse engineering, the verification of the signature can be subverted.
So, you'd actually need a trusted kernel function to verify the binary before execution. Open source kernels would appear to have the benefit of proper peer review and cross-examination. That kernel would really need TPM hardware to assist. You'd then be down to physical security (you have to trust the hardware vendor and the physical security of your hosting location).
Also, you'd need NX kernel features (or like the Win32 DEP), to prevent execution of writable memory. Inversely, you'd need kernel protection of the executable segments (this is usually the case anyway, to allow sharing of memory maps, IIRC).
All of which just begs the question: what do you need this kind of security for. Depending on the answer, implementing the above, and more, might even be reasonable.
$0.02
The point of const
is that the identifier is a constant. If someone is using const_cast
or other tricks to subvert your constant then their program will have undefined behavior. I wouldn't worry about this in practice.
I believe, once you compile your code with some optimizations, the compiler emits the machine code with the constant literal (such as 3.1412
), instead of the variable name (such as PI
). So the machine code most likely will not have symbols (i.e PI
) which you use in your code.
static const double PI = 3.14;
prevents modifying this constant from other modules compiled with this one. OTOH, it doesn't saves from changing this constant using HEX editor or in-memory.
The other solution (not recommended but possible) is to use
#define PI 3.14
And, yes, you can use
M_PI
constant. See this question
I would assume that the actual memory space that the const resides in would have to be modified for it to be modified. Unless you have a clear reason/issue to do a check like this, I would say that it is not required. I have never known anything to require a check of the value of a constant.
If you have a declared non-volatile const
variable, there is no legal way for it to be modified externally.
Writing to a const
variable is undefined behavior. And declaring a extern double PI;
in another translation unit will declare a different variable than what you declared, because yours has internal linkage, which means it can only be redeclared in the same translation unit.
And even if it were to declare the same variable, then behavior would be undefined (because of a const
/ non-const
mismatch in type identity).
Constant variables cannot be changed without invoking undefined behavior. There is no point in defending against that.
精彩评论