www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Unexpected behavior when casting away immutable

reply Mike Parker <aldacron gmail.com> writes:
I have a situation where I would like to demonstrate violating 
the contract of immutable (as an example of what not to do), but 
do so without using structs or classes, just basic types and 
pointers. The following snippet works as I would expect:

```
immutable int i = 10;
immutable(int*) pi = &i;
int** ppi = cast(int**)&pi;
writeln(*ppi);
int j = 9;
*ppi = &j;
writeln(*ppi);
```

Two different addresses are printed, so I've successfully 
violated the contract of immutable and changed the value of pi, 
an immutable pointer. However, this does not work as I expect.

```
immutable int x = 10;
int* px = cast(int*)&x;
*px = 9;
writeln(x);
```

It prints 10, where I expected 9. This is on Windows. I'm curious 
if anyone knows why it happens.
Sep 22 2015
next sibling parent reply Vladimir Panteleev <thecybershadow.lists gmail.com> writes:
On Wednesday, 23 September 2015 at 03:39:02 UTC, Mike Parker 
wrote:
 ```
 immutable int x = 10;
 int* px = cast(int*)&x;
 *px = 9;
 writeln(x);
 ```

 It prints 10, where I expected 9. This is on Windows. I'm 
 curious if anyone knows why it happens.
Essentially, because x is immutable, the compiler optimizes writeln(x) to writeln(10). This seems to happen even without -O.
Sep 22 2015
parent Mike Parker <aldacron gmail.com> writes:
On Wednesday, 23 September 2015 at 03:50:44 UTC, Vladimir 
Panteleev wrote:
 On Wednesday, 23 September 2015 at 03:39:02 UTC, Mike Parker 
 wrote:
 ```
 immutable int x = 10;
 int* px = cast(int*)&x;
 *px = 9;
 writeln(x);
 ```

 It prints 10, where I expected 9. This is on Windows. I'm 
 curious if anyone knows why it happens.
Essentially, because x is immutable, the compiler optimizes writeln(x) to writeln(10). This seems to happen even without -O.
I see. Thanks.
Sep 22 2015
prev sibling parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Wednesday, 23 September 2015 at 03:39:02 UTC, Mike Parker 
wrote:
 I have a situation where I would like to demonstrate violating 
 the contract of immutable (as an example of what not to do), 
 but do so without using structs or classes, just basic types 
 and pointers. The following snippet works as I would expect:

 ```
 immutable int i = 10;
 immutable(int*) pi = &i;
 int** ppi = cast(int**)&pi;
 writeln(*ppi);
 int j = 9;
 *ppi = &j;
 writeln(*ppi);
 ```

 Two different addresses are printed, so I've successfully 
 violated the contract of immutable and changed the value of pi, 
 an immutable pointer. However, this does not work as I expect.

 ```
 immutable int x = 10;
 int* px = cast(int*)&x;
 *px = 9;
 writeln(x);
 ```

 It prints 10, where I expected 9. This is on Windows. I'm 
 curious if anyone knows why it happens.
violating immutable is undefined behaviour, so the compiler is technically speaking free to assume it never happens. At the very least, neither snippet's result is guaranteed to show a change or not. At the most, literally anything can happen.
Sep 22 2015
next sibling parent reply Mafi <mafi example.org> writes:
On Wednesday, 23 September 2015 at 05:24:05 UTC, John Colvin 
wrote:
 On Wednesday, 23 September 2015 at 03:39:02 UTC, Mike Parker 
 wrote:
...
 ```
 immutable int x = 10;
 int* px = cast(int*)&x;
 *px = 9;
 writeln(x);
 ```

 It prints 10, where I expected 9. This is on Windows. I'm 
 curious if anyone knows why it happens.
violating immutable is undefined behaviour, so the compiler is technically speaking free to assume it never happens. At the very least, neither snippet's result is guaranteed to show a change or not. At the most, literally anything can happen.
In essence, this code snippet is even better than the OP expected in showing why you shouldn't cast away immutable.
Sep 23 2015
parent Mike Parker <aldacron gmail.com> writes:
On Wednesday, 23 September 2015 at 11:38:38 UTC, Mafi wrote:
 On Wednesday, 23 September 2015 at 05:24:05 UTC, John Colvin 
 wrote:
 On Wednesday, 23 September 2015 at 03:39:02 UTC, Mike Parker 
 wrote:
...
 ```
 immutable int x = 10;
 int* px = cast(int*)&x;
 *px = 9;
 writeln(x);
 ```

 It prints 10, where I expected 9. This is on Windows. I'm 
 curious if anyone knows why it happens.
violating immutable is undefined behaviour, so the compiler is technically speaking free to assume it never happens. At the very least, neither snippet's result is guaranteed to show a change or not. At the most, literally anything can happen.
In essence, this code snippet is even better than the OP expected in showing why you shouldn't cast away immutable.
Yes, that's true. I think using both snippets drives the point home pretty well.
Sep 23 2015
prev sibling parent reply bachmeier <no spam.com> writes:
On Wednesday, 23 September 2015 at 05:24:05 UTC, John Colvin 
wrote:

 violating immutable is undefined behaviour, so the compiler is 
 technically speaking free to assume it never happens. At the 
 very least, neither snippet's result is guaranteed to show a 
 change or not. At the most, literally anything can happen.
I was not aware that you could "violate" immutable. In that case, it's not immutable.
Sep 23 2015
next sibling parent John Colvin <john.loughran.colvin gmail.com> writes:
On Wednesday, 23 September 2015 at 14:34:07 UTC, bachmeier wrote:
 On Wednesday, 23 September 2015 at 05:24:05 UTC, John Colvin 
 wrote:

 violating immutable is undefined behaviour, so the compiler is 
 technically speaking free to assume it never happens. At the 
 very least, neither snippet's result is guaranteed to show a 
 change or not. At the most, literally anything can happen.
I was not aware that you could "violate" immutable. In that case, it's not immutable.
immutable is guaranteed to be enforced at the type-system level. If you deliberately break the type system and tell the compiler to modify data that in actual fact is immutable, then that is undefined behaviour. If you're lucky, the data could have some protection such that writing to it will trigger a fault at the hardware level, but that's definitely *not* guaranteed.
Sep 23 2015
prev sibling parent Dicebot <public dicebot.lv> writes:
On Wednesday, 23 September 2015 at 14:34:07 UTC, bachmeier wrote:
 I was not aware that you could "violate" immutable. In that 
 case, it's not immutable.
You can violate absolutely everything in a system language with casts and pointers. That is exactly what makes it system language. But you do so only by intentionally and explicitly abandoning type system and domain of well-defined behaviour. Compiler could as well decide to put it in RO section of executable resulting in app crash at runtime (that happens with string literals on Linux). Any cast means "I know what I am doing and I am fully prepared to get burned".
Sep 23 2015