the same memory location can have different values

  • Thread starter Floare Augustin Theodor
  • Start date
F

Floare Augustin Theodor

Hi,

I've stumbled on a weird situation where the same memory location
presents two different values for its content.
Here is the code:

#include <iostream>

int main()
{
const int ct = 10;
int* p = (int*)&ct;

*p = 332;

std::cout << "addresses: " << p << " and " << &ct << std::endl;
std::cout << "values: " << *p <<" and "<< ct << std::endl;

return 0;
}


And the output is:

"addresses: 0030F9EC and 0030F9EC
values: 332 and 10"

How it is possible to have different values (332 and 10) for 0030f9EC
memory location?

Thanks,
Teo
 
R

Rolf Magnus

Floare said:
Hi,

I've stumbled on a weird situation where the same memory location
presents two different values for its content.

No. You have found an instance of undefined behaviour.
Here is the code:

#include <iostream>

int main()
{
const int ct = 10;
int* p = (int*)&ct;

*p = 332;

The above line invokes undefined behaivour. You are not allowed to write to
a variable that was initially declared const. Anything can happen in your
program after executing that line.
 
N

Neelesh

Hi,

I've stumbled on a weird situation where the same memory location
presents two different values for its content.
Here is the code:

#include <iostream>

int main()
{
        const int ct = 10;
        int* p = (int*)&ct;

Casting away constness of objects that are actually const results in
undefined behavior.
        *p = 332;

        std::cout << "addresses: " << p << " and " << &ct << std::endl;
        std::cout << "values: " << *p <<" and "<< ct << std::endl;

        return 0;

}

And the output is:

"addresses: 0030F9EC and 0030F9EC
values: 332 and 10"

How it is possible to have different values (332 and 10) for 0030f9EC
memory location?

Once the behavior is undefined, all bets are off on such a program.
 
G

gw7rib

On 6 June, 17:49, Floare Augustin Theodor

As someone used to put it, "If you lie to the compiler, it will get
its revenge".

int main()
{
        const int ct = 10;

Here you are promising that ct is const. It has the value 10. This
will not change. No siree!
        int* p = (int*)&ct;

        *p = 332;

And here you change it. Have you considered a career as a politician?
        std::cout << "addresses: " << p << " and " << &ct << std::endl;
        std::cout << "values: " << *p <<" and "<< ct << std::endl;


        return 0;

}

And the output is:

"addresses: 0030F9EC and 0030F9EC
values: 332 and 10"

The first of these is the value of *p. It's 332, as that's what you
set it to.

The second of these is the value of ct. ct had the value of 10, and is
not (you said) going to change, so it must (the compiler may presume)
still be 10. There's no need to look it up, so the computer doesn't
spot that it has, in fact, changed.
How it is possible to have different values (332 and 10) for 0030f9EC
memory location?

Hope that helps.
Paul.
 
F

Floare Augustin Theodor

No. You have found an instance of undefined behaviour.



In “C The Complete Reference”, Herbert Schildt says: “Don't forget, a
const variable can be modified by something that is outside the
program. For example, a hardware device can set its own
value” (translated from the Romanian version)

So, it means that “const” counts only for the compiler, to check the
code for inconsistencies. But for the object code, the “const”
property is not present in any way, is it?

“Undefined behavior” is a theory behind C++. The real implementation
can run in “undefined behavior” only if something wrong happened at
runtime.

In this case, the program finishes its task, by printing the values
(the same result is for g++/Linux and Visual C++ 2008 Express Edition/
Windows). So, because the “undefined behavior” is the same on the two
compilers, it means that they implement the “undefined behavior” in
the same manner, by having a memory location with two different
values. And because it is the same, it makes me say that the
implementors of compilers chose a “defined behavior” for an “undefined
behavior” case of the C++ theory.

I hope that someone could come with an explanation for this result,
because I am not content with the “undefined behavior” solution.

Thanks,
Teo
 
R

Rolf Magnus

Floare said:
In “C The Complete Referenceâ€, Herbert Schildt says:

This book has a very bad reputation.
“Don't forget, a const variable can be modified by something that is
outside the program. For example, a hardware device can set its own
value†(translated from the Romanian version)

This is only true for special variables like hardware registers. Such
variables must be declared volatile, otherwise the compiler will assume that
nothing outside your program will change them or depend on their current
value.
So, it means that “const†counts only for the compiler, to check the
code for inconsistencies. But for the object code, the “constâ€
property is not present in any way, is it?

No, that's not the case. First of all, you are mixing up C and C++. Second,
a variable can e.g. be put in read-only memory areas if it's const. Then an
attempt to write to it could easily result in a crash.
“Undefined behavior†is a theory behind C++.

Yes. Basically, it is supposed to give the "implementation" (meaning the
combination of compiler, runtime library and hardware) more freedom. It
makes implementations simpler and gives better opportunity for optimization.
The real implementation can run in “undefined behavior†only if something
wrong happened at runtime.

"Something wrong" can result from invoking undefined behavior in the C++
code.
In this case, the program finishes its task, by printing the values
(the same result is for g++/Linux and Visual C++ 2008 Express Edition/
Windows). So, because the “undefined behavior†is the same on the two
compilers, it means that they implement the “undefined behavior†in
the same manner, by having a memory location with two different
values.

They don't have a memory location with two values. They simply optimize
accesses to the variable away, because they assume that it hasn't changed.
After all, you told the compiler that it will never change. That
optimization might not happen in all cases though, and it's not defined when
it does. This means that you shouldn't try to derive any conclusions from
the observed behavior, because it might change with compiler, compiler
verson or even the compiler's command line options. It is likely not even
documented anywhere. That's why it's called "undefined".
And because it is the same, it makes me say that the
implementors of compilers chose a “defined behavior†for an “undefined
behavior†case of the C++ theory.

That's exactly what you shouldn't do.
And btw, I have seen compilers behave differently, including g++ for other
platforms.
I hope that someone could come with an explanation for this result,
because I am not content with the “undefined behavior†solution.

Why? The basic idea of "undefined behavior" is that you "shouldn't try this
at home". And if you don't, it doesn't really matter what happens.
 
A

Alf P. Steinbach

* Floare Augustin Theodor:
In “C The Complete Reference”, Herbert Schildt says: “Don't forget, a
const variable can be modified by something that is outside the
program. For example, a hardware device can set its own
value” (translated from the Romanian version)

I guess you're attempting some trolling-light by quoting Herbert Schildt, but as
it happens in this instance he's right, although only by virtue of making so
vague a statement that it's practically meaningless.

An originally const object can't have its value changed in a correct program.

If its value is changed then you have UB, which means all bets are off: one
reference to it may produce the original value, another the changed value.


So, it means that “const” counts only for the compiler, to check the
code for inconsistencies. But for the object code, the “const”
property is not present in any way, is it?

Constness can be present in the machine code in a number of ways.

First, the compiler may completely or partially optimize away an originally
const variable, as you discovered.

Second, the compiler may elect to place an originally const variable in read
only memory, so that write accesses are detected.

Third, although only of academic interest, a compiler may implement "fat
pointers" that keep information about whatever they refer to. Even in the
acedademic's wildest dreams this is usually limited to array bounds. But it
could in principle also include original constness of the referent.

“Undefined behavior” is a theory behind C++.

I'm sorry, no, it isn't.

It is a term defined by the C++ standard.

There are some other similar terms, like "unspecified behavior", and the
differences have to do with whether diagnostics are required, and whether the
behavior for any particular compiler needs to be documented.

The real implementation
can run in “undefined behavior” only if something wrong happened at
runtime.

Sorry, that's not the case.

For example, the second case of Undefined Behavior mentioned in the standard is
in §2.1/2, which notes that you have UB if a line continuation produces a
"universal-character-name" (like \u1234).

The UB says by definition that the standard then imposes no requirements on the
program results, or even on whether the compiler does produce an executable.

In short, from the formal point of view anything or nothing may happen.

In practice, with many cases of UB we still do have some expectations about
possible, practically reasonable behaviors. The stories about hate mails being
sent to presidents of superpowers, and nasal demons starting to fly out your
nose, not to mention the erasure of all Swedish pop music from Norwegian radio
stations (which might not be as catastrophic as it might sound (oops, I think
perhaps that was ambiguous)), are simply exaggerations. But even when you get
some reasonable result with some compiler, you can't count on it with other
compilers.

In this case, the program finishes its task, by printing the values
(the same result is for g++/Linux and Visual C++ 2008 Express Edition/
Windows). So, because the “undefined behavior” is the same on the two
compilers, it means that they implement the “undefined behavior” in
the same manner,

Sorry, no, it doesn't mean that.

It means they've produced programs that yield the same external effect.

The same external effect can be brought about in a zillion different ways.

by having a memory location with two different
values.

Sorry, no, and that's stupid.

A given memory location has only one value at a given time.

What happened in your case (I think it was your case, but I'm not going to check
back up the thread) was that you lied to the compiler, so the compiler optimized
away the actual use of a memory location: it used the value directly in the
machine code.

And because it is the same, it makes me say that the
implementors of compilers chose a “defined behavior” for an “undefined
behavior” case of the C++ theory.

Sorry, no, that conclusion does not follow.

They're allowed to defined the behavior in a case of formal UB, and one may rely
on such documented behavior in practice.

But the behavior is only defined if it's defined: by happenchance getting the
same external effect with two compilers does not make the behavior defined.

I hope that someone could come with an explanation for this result,
because I am not content with the “undefined behavior” solution.

Assuming by "solution" you mean "explanation": you should be content with that
:), see above.

For otherwise you'll have to figure out where the behavior is documented, and
restrict yourself to use of that compiler, or those compilers.

Which is just a lot of work for no gain whatsoever.


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

* Jack Klein:
I could prove in a very few lines that 1 is equal to 2, or for that
matter that any finite real number is equal to any other finite real
number merely by committing the mathematical undefined behavior of
dividing by zero.

I think you mean, dividing 0 by 0.

Dividing x/0 where x != 0 is no problem, except if you insist on the result
having completely general number-like properties... ;-)

And the nice thing is that multiplication and division of those kinds of
beasties can be implemented very simply by relying on the similarity to
properties of complex numbers; only a bit of renaming required. Which can be
used to optimize quite a few things, like Dempster-Shafer evidence combination,
or Lagrange interpolation. Although both those examples are quite academic.


Cheers & hth.,

- Alf
 
F

Floare Augustin Theodor

There is no such thing as a "const variable" in C++, or C for that
matter.

I think a “constant variable” is a valid expression because “variable”
is the name for the memory location that can hold a value. And because
that value does not change, comes the name “constant variable”. A
variable has the right to vary or to be constant.
 
F

Floare Augustin Theodor

Undefined behavior is not restricted to run time, and not restricted
by your opinion.

How an “undefined behavior” can be present before the runtime?
 
F

Floare Augustin Theodor

I listen to your advice and I've looked at the generated assembler
code, here it is:

….....................
_TEXT SEGMENT
_b$ = -44 ; size = 4
_a$ = -32 ; size = 4
_p$ = -20 ; size = 4
_ct$ = -8 ; size = 4
_main PROC ; COMDAT

; 9 : {

push ebp
mov ebp, esp
sub esp, 240 ; 000000f0H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-240]
mov ecx, 60 ; 0000003cH
mov eax, -858993460 ; ccccccccH
rep stosd

; 10 :
; 11 : const int ct = 10;

mov DWORD PTR _ct$[ebp], 10 ; 0000000aH

; 12 : int* p = (int*)&ct;

lea eax, DWORD PTR _ct$[ebp]
mov DWORD PTR _p$[ebp], eax

; 13 :
; 14 : *p = 332;

mov eax, DWORD PTR _p$[ebp]
mov DWORD PTR [eax], 332 ; 0000014cH

; 15 :
; 16 : int a = ct + 1;

mov DWORD PTR _a$[ebp], 11 ; 0000000bH

; 17 : int b = *p + 1;

mov eax, DWORD PTR _p$[ebp]
mov ecx, DWORD PTR [eax]
add ecx, 1
mov DWORD PTR _b$[ebp], ecx

….....................

From this assembler code the thoughts that comes are:
a. everywhere the constant ct is used, its value, 10, is replaced by
compiler (int a = ct + 1; becomes int a = 11;)
b. the address of ct itself resides in the stack and that memory
location can change its value (initial value is 10 than becomes 332)
c. the “const” property is not present in the object code
d. there is no “undefined behavior” in the assembler code that can go
to a crash
 
P

peter koch

I listen to your advice and I've looked at the generated assembler
code, here it is:

…..................... [snip]
From this assembler code the thoughts that comes are:
a. everywhere the constant ct is used, its value, 10, is replaced by
compiler (int a = ct + 1; becomes int a = 11;)
Yes. That optimisation is perfectly valid.
b. the address of ct itself resides in the stack and that memory
location can change its value (initial value is 10 than becomes 332)
This is in no way guaranteed. The compiler is free to place the
variable whereever it wants to, and a newer compiler or a change in
compiler settings might cause it to do so.
c. the “const” property is not present in the object code
That property is a C++ concept and only exists in the C++ source-code.
d. there is no “undefined behavior” in the assembler code that can go
to a crash
If you come to assembler, I doubt you would experience "undefined
behaviour" ever, and again what we are discussing here is C++undefined
behaviour, and that kind of behaviour can never exist in assembly
code.

/Peter
 
R

Rolf Magnus

Floare said:
I think a “constant variable†is a valid expression because “variableâ€
is the name for the memory location that can hold a value.

That's called "object". A variable is an object that has a name.
 
J

James Kanze

In “C The Complete Reference”, Herbert Schildt says: “Don't
forget, a const variable can be modified by something that is
outside the program. For example, a hardware device can set
its own value” (translated from the Romanian version)

The statement is simply false. Given Schildt's repuation, it
doesn't really surprise me.
So, it means that “const” counts only for the compiler, to
check the code for inconsistencies. But for the object code,
the “const” property is not present in any way, is it?

No, it means that Schildt doesn't know what he's talking about.
“Undefined behavior” is a theory behind C++. The real
implementation can run in “undefined behavior” only if
something wrong happened at runtime.

Undefined behavior is a term defined by the C++ (and the C)
standard. If your program contains an instance of undefined
behavior, then the behavior of your program is undefined, at
least as far as C++ is concerned. (Some implementations may
define specific cases of undefined behavior to do something
particular on that implementation. I don't know of any which
define the effect of modifying a const variable, however.)
In this case, the program finishes its task, by printing the
values (the same result is for g++/Linux and Visual C++ 2008
Express Edition/ Windows). So, because the “undefined
behavior” is the same on the two compilers, it means that they
implement the “undefined behavior” in the same manner, by
having a memory location with two different values. And
because it is the same, it makes me say that the implementors
of compilers chose a “defined behavior” for an “undefined
behavior” case of the C++ theory.

No. It means that both compilers see the const, and know your
program doesn't modify the variable. And so assume that the
variable isn't modified. Change the code even slightly, and you
might get different results.
I hope that someone could come with an explanation for this
result, because I am not content with the “undefined behavior”
solution.

I'm afraid you'll have to be content with it, because it is the
only correct explination. Undefined behavior was introduced
into the standard for a number of reasons. One (the one
probably acting here) is to allow various optimizations; if I
write something like *p = ++i, for example, the compiler knows
that *p cannot refer to i, and is free to reorder the
assignments. In your case, the compiler is free to assume that
the const variable doesn't change, and use the value, rather
than actually reading what the variable contains.
 
J

James Kanze

This book has a very bad reputation.

Which his quote bears up. Assuming nothing lost in
translation---some of the translations I've seen have been very
bad as well, and the early translations of Stroustrup into
French would have given him a bad reputation as well. (In the
case of Stroustrup in French, one of the participants in
fr.comp.lang.c++ signaled the problem to Stroustrup, and he,
Stroustrup and the publisher then worked to fix it, so current
printings should be OK.)
This is only true for special variables like hardware
registers. Such variables must be declared volatile, otherwise
the compiler will assume that nothing outside your program
will change them or depend on their current value.

There are two orthogonal concepts here: const (applied to a
variable) means that the program will never change its value;
volatile means that the value may change due to causes outside
the program (whether the variable is const or not).

[...]
"Something wrong" can result from invoking undefined behavior
in the C++ code.

And the "something wrong" isn't just a runtime concept. A
compiler can refuse to compile a program with undefined
behavior. Or compile it to do something completely different.
("#define int 0" causes undefined behavior if it occurs
before the inclusion of a standard header. And it's most likely
to cause the program to fail to compile. "#define while if"
causes undefined behavior as well, if it occurs before the
inclusion of a standard header---in this case, there's a fair
chance that the code will still compile, but I imagine that some
of the algorithms in <algorithm> will behave somewhat
strangely.)
 
J

James Kanze

* Floare Augustin Theodor:
I guess you're attempting some trolling-light by quoting
Herbert Schildt, but as it happens in this instance he's
right, although only by virtue of making so vague a statement
that it's practically meaningless.

Not as far as C++ is concerned. He's confusing const and
volatile. (Of course, you can interpret his statement more
loosely, to refer to changes not recognized by the language:
alpha particles which modify the contents of memory, for
example. In that case, of course, it is totally meaningless.)
An originally const object can't have its value changed in a
correct program.
If its value is changed then you have UB, which means all bets
are off: one reference to it may produce the original value,
another the changed value.

If a variable is declared volatile, then the compiler is
supposed to take into account a possible change of value. (Most
don't, actually, on modern architectures, but that's beside the
point.)

This has nothing to do with const, however.
 
J

James Kanze

* Jack Klein:
I think you mean, dividing 0 by 0.
Dividing x/0 where x != 0 is no problem, except if you insist
on the result having completely general number-like
properties... ;-)

It's obviously a question of how you define /, but if you are
defining it as a closed operation over the set of reals, then
division by zero is excluded (or you can't define it). And
IIRC, the "proof" I think that Jack was referring to involves
dividing both sides of an equality by (a-b), having previously
postulated that a and b are equal.
 
J

James Kanze

That's called "object". A variable is an object that has a name.

Yes, but since a variable is an object, the properties of that
object can be applied to it. The C++ standard does use the term
"const variables" (in §5.19), although in other contexts, it
prefers "const object" (doubtlessly because not all objects are
variables).
 
A

Alf P. Steinbach

* Jack Klein:
* Jack Klein:
I think you mean, dividing 0 by 0.

Dividing x/0 where x != 0 is no problem, except if you insist on the result
having completely general number-like properties... ;-)

[snip]

No,

You mean "yes". :)

I'll show you what I meant. Excuse errors in the format, I
haven't attempted to write a formal proof since high school, a very
long time ago.

Given: any finite real numbers 'x' and 'y'

Prove: the value of 'x is equal to the value of 'x' + 'y'

1: x * 0 = (x + y) * 0

2: (x * 0) / 0 = ((x + y) * 0) / 0

QED: x = (x + y)

I don't remember the names of the principals, but:

1 is true based on the fundamental properties of multiplication by 0

2 appears to be valid based on the fact that if equal quantities are
divided by equal amounts, the results are equal

If 1 and 2 are both true and/or valid, this represents absolute proof
that 1 is equal to 2, for example, or for that matter that any two
finite real numbers are exactly equal to each other.

The reason that this is not a proof that all finite real numbers are
equal is the fact that 2. is not valid, because division by o is
undefined in mathematics.

Eq. 2 is not valid because 0/0 is indeterminate (it is the set of all numbers),
and with x and y real numbers the parenthesized expressions are 0, yielding 0/0.


Cheers,

- Alf (where is Hari Seldon when we need him?)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,193
Latest member
TopCryptoTaxSoftwares2024

Latest Threads

Top