2

I wanted to prove that there is nothing known as (A protected memory address) and the whole story is just about the compiler, or the OS, or whatever application the hosted app is running on just make some checking on read and write requests the hosted app send to its superior process and this superior app or whatever you call it decide if this child process has the right to read or write to this specific memory location but this c++ code doesn't work in this essence so why :

#include <iostream>
int main()
{
    const int x = 10;
    std::cout << &x << std::endl; // So i can view address of x
    std::cout << "x Before is equal "<< x <<std::endl;

    int y ;
    std:: cin >> std::hex >>y;

    int *pinter = (int*)y ;
    *pinter = 20;
    std::cout << "x After is equal "<< x <<std::endl;
}

This code is supposed to get around the concept of c++ compiler setting x variable type to const int so that neither pointer to the variable (unlike in C in which pointers to constants can change the value of constant ) nor references to the variable can change the variable so this code is supposed to get address of variable x (of course after it's printed out) and then a pointer do the rest of the work , so what i messed here , cause it seams like this memory location is hardware protected( I know it's not but I am very confused)

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
KMG
  • 1,433
  • 1
  • 8
  • 19
  • 8
    It's Undefined Behaviour, meaning absolutely anything can happen. There is no "memory protection" of any sorts in C++ (although it's not forbidden, implementations can use it depending on OS, architecture etc.). For example, it's possible that you did in fact change the memory of `x`, but compiler knows that `x` cannot change so it optimizes print. – Yksisarvinen Jun 03 '20 at 08:53
  • 2
    There is no such thing as "C++ hardware". – underscore_d Jun 03 '20 at 09:01
  • Does this really can happen i mean can cout just print wrong value of a variable – KMG Jun 03 '20 at 09:03
  • 2
    If your program invokes undefined behaviour, then anything can happen. What that means in practice is that compilers can act like your code doesn't exist, or like it does something else that would be valid, or like it's totally random. There's a simple answer: don't do that. – underscore_d Jun 03 '20 at 09:04

3 Answers3

7

This code is supposed to get around the concept of c++ compiler setting x variable type to const int so that [...]

You can break the rules of the language, but then your code is not valid C++. You shall not modify something that is qualified as const. If you do you have undefined behavior. As compilers are made to compile valid C++, they are not mandated to do anything meaningful to non-valid code and the result can be anything or nothing.

As already said in a comment:

const has nothing to do with hardware or memory. It is an agreement between you and your compiler and you broke that agreement. As a reward your compiler will do anything to your code, but not necessarily what you expect.

You tried to trick the compiler by making the modification at runtime such that at compile time the compiler cannot know that you will modify a const. However, you did declare x as const so the compiler will assume that its value will not change. If you still modify the value of x anything can happen.

PS: Rather frequently people come up with hacks to "proove" that private isn't really private, cosnt isn't really const and similar. The thing is: Those are facilities that are supposed to help you to make less mistakes and write cleaner code. If you try hard to cirumvent those facilites you will manage to do so (sometimes even without invoking UB). However, this "prooves" nothing except the possiblity to shoot yourself in the foot. C++ is not Java, it does not hold your hand and tries to prevent you from every possible mistake that you can make. In that regard C++ is closer to Pythons "we are all constenting adults here".

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • Thanks a lot so Your answer is simply That even if the concept is correct the implementation will be wrong or at least doesn't have any benefits so the whole thing is because of the compiler – KMG Jun 03 '20 at 09:14
  • @ahmedamr "the whole thing" is that you are not writing instructions for your cpu and you are not working on memory when writing code. Instead you write an abstract definition of what your program should do after being compiled. Your compiler uses that to create the actual program code. When you declare something as `const` then it is `const` by definition. Moreover, taking an arbitrary memory adress, assuming there is an object and modifying that object, fails miserably in general. – 463035818_is_not_an_ai Jun 03 '20 at 09:19
  • @ahmedamr The point is very simple: modifying something that was declared `const` invokes undefined behavior. The end, full stop. Once undefined behavior is invoked, all bets are off -- the compiler can emit code that does _anything at all_ and you can no longer reason about the program. What you learned in your sample program is _not_ that the compiler pretends you didn't modify the variable -- _that's just one possible outcome._ __Any other outcome is just as possible.__ – cdhowie Jun 03 '20 at 09:23
  • @cdhowie (I have to admit, I also didnt read the code in all details when writing this answer. ) Note that the compiler has no way to know that this code will modify a `const int` at runtime. That doesnt make it less UB though – 463035818_is_not_an_ai Jun 03 '20 at 09:25
  • @idclev463035818 Indeed -- in fact, the compiler is free to assume that the value doesn't change _because that's what the programmer said._ – cdhowie Jun 03 '20 at 09:26
  • @idclev463035818 yes that the whole point how does the compiler know that i was going to change const int x at runtime, I mean the address is a user input , so it can be anything so how this resulted in an UB – KMG Jun 03 '20 at 13:41
  • @ahmedamr the compiler "knows" that the value of `x` never changes. It also "knows" that what is stored at `&x` never changes its value. Now this is purely hypothetical: Whenever you call `std::cout << *ptr;`, where `ptr == &x`, the compiler could replace that with `std::cout << 10;`, because you cannot possibly tell the difference (unless you have undefined behavior) – 463035818_is_not_an_ai Jun 03 '20 at 13:45
  • @ahmedamr different scenario: After the code you have, you put `if (x == 10) {...}`, the compiler can replace that by `if (true) {...`, without changing the observable behavior of the program (because it assumes that `x` never changes its value) – 463035818_is_not_an_ai Jun 03 '20 at 13:48
  • @ahmedamr when your code has UB there is no guarantee that something bad will happen like a crash or wrong output. What is bad about UB is that you also get no guarantee that something good will happen ;) – 463035818_is_not_an_ai Jun 03 '20 at 13:51
  • @ahmedamr but I understand that the crux of the question is that the compiler has no way to see that there is something wrong and somehow I missed this important detail first. I would need to rewrite the answer as a whole to address that more clearly, maybe I will do that later... – 463035818_is_not_an_ai Jun 03 '20 at 13:53
  • @idclev 463035818 Thanks alot now i understand the whole thing. That i want to edit the question with the answer of your comment of (After the code you have, you put if (x == 10) {...}, the compiler can replace that by if (true) {..., without chang) so if someone else have a question like this can see this helpfull comment, so is there a like a pointer in stackoverflow to point to a comment or something like that to indicate an answer or you can copy paste this comment in your answer – KMG Jun 03 '20 at 15:50
  • @ahmedamr in general it isnt nice to change the question substantially after you already got answers. Maybe I will add a bit to the answer, I just dont have time now – 463035818_is_not_an_ai Jun 03 '20 at 16:45
2

const is provided to: 1. Annotate that the value is not supposed to be changed 2. Allow the compiler to optimize the code better because of the fact that it’s not supposed to be changed.

You didn’t have to jump through all of these hoops, you could have just used ‘const_cast’ to change the const’ness.

The compiler “helps” you to enforce the const’ness but as you shown, there are many ways to bypass it. If you will change a const value will yield UB.

Enosh Cohen
  • 369
  • 2
  • 11
  • Yup, if you modify an object that was originally declared as `const`, it's UB. `const_cast` is only legitimate for allowing non-`const` access, via an ostensibly `const` reference or pointer, to an object that was originally declared as non-`const`. – underscore_d Jun 03 '20 at 09:05
  • const cast does not "change the constness". If the object is `const` then also using a `const_cast` will invoke undefined behavior when something `const` is modified. You can for example `const_cast` on a `const& int` that refers to a `int` but not to a `const& int` that refers to a `const int` – 463035818_is_not_an_ai Jun 03 '20 at 09:10
  • From cppref: “const_cast makes it possible to form a reference or pointer to non-const type that is actually referring to a const object or a reference or pointer to non-volatile type that is actually referring to a volatile object. Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue results in undefined behavior.” https://en.cppreference.com/w/cpp/language/const_cast – Enosh Cohen Jun 03 '20 at 09:10
  • 1
    You can cast away constness on a reference/pointer to an originally const object, but you must not _modify_ via the resulting non-const reference/pointer, because that gives UB. If you have to do that in real code, it means you have broken code or are using a broken API. So, yeah, it's possible, but it shouldn't ever be _necessary_. – underscore_d Jun 03 '20 at 09:12
  • There is no doubt that it’s UB. I only wrote that he didn’t needed to do all of the cout/cin “magic” to strip the const from the variable. – Enosh Cohen Jun 03 '20 at 09:15
1

The reason why it doesn't work (apart from the UB and that the compiler might optimize the code knowing that x is const) is probably because int y can not hold the address of x if you run on a 64 bit system. The address is most likely a 64 bit address with one of the top 32 bits set - and your int is most likely 32 bit.

Use the correct type to store the address and make x volatile const and you'll still have UB - but it might just work as you expect.

#include <cstdint>
#include <iostream>

int main()
{
    volatile const int x = 10;    

    std::cout << "x Before is equal "<< x <<std::endl;

    std::uintptr_t y = (std::uintptr_t) &x;

    int *pinter = (int*) y;
    *pinter = 20;

    std::cout << "x After is equal "<< x <<std::endl;
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Thanks a lot it actually worked just by adding volatile keyword, But why volatile keyword solve it all , I mean if I am using the original code the compiler is supposed to not Having any idea that i am going to change the const x ( ie: enter the address of const x )so , how when the user input the address of the const x the compiler seems to step in again to prevent this from happening i mean the job of the compiler is supposed to be ended when the program is running right ? – KMG Jun 03 '20 at 13:15
  • If `volatile` was sufficent you are either running on a 32 bit machine or your `x` was placed at an address only using the lower 32 bits or your `int` is 64 bits. `volatile` tells the compiler that it can't make the assumption that it has full control over the variable. It may be mapped to hardware and changed totally out of the running program's control - so the optimizing part can't be as aggressive. In this case the `const` only promises that the program itself won't change the variable (which it does anyway). – Ted Lyngmo Jun 03 '20 at 13:20
  • @ahmedamr The link to `volatile const` in my answer explains it in more detail. – Ted Lyngmo Jun 03 '20 at 13:25