Questions about compilers const optimizations

G

Gianguz

The following code compiled with gcc version 3.3.4 20040623 (Gentoo
Linux 3.3.4-r1, ssp-3.3.2-2, pie-8.7.6) produce a segmentation fault
and has a size
of 9095 byte on my machine:

#include <iostream>

using namespace std;

const bool v = true;

void modifyConst() {

const bool tmp = v;

const_cast<bool&>(v) = !tmp;

return;
}

int main() {

do {
if (v) {

cout << "FOREVER HERE?!?!" << endl;

modifyConst();
}

else {
cout << "THIS CODE WILL NOT BE GENERATED?!" << endl;
}
}

while(v);
}

The same code with "bool v = true;" instead of "const bool v = true;"
has a size of 9184 byte and runs with no error.

Had the compiler removed the 'else branch' and the 'while cmp
instruction' only looking at the const declaration? If so, why it
can't handle the assignment (with cast) in the modifyConst? It should
be able to understand that what was previously considered a 'safe
const' (regarding to optimizations and expressions reduction) now is
no more a 'safe' one.

Thanks,

Gianguglielmo
 
A

Andre Kostur

(e-mail address removed) (Gianguz) wrote in
The following code compiled with gcc version 3.3.4 20040623 (Gentoo
Linux 3.3.4-r1, ssp-3.3.2-2, pie-8.7.6) produce a segmentation fault
and has a size
of 9095 byte on my machine:

#include <iostream>

using namespace std;

const bool v = true;

void modifyConst() {

const bool tmp = v;

const_cast<bool&>(v) = !tmp;

Program may do anything it wants to at this point. You are modifying a
const object, and thus Undefined Behaviour is invoked.
return;
}

int main() {

do {
if (v) {

cout << "FOREVER HERE?!?!" << endl;

modifyConst();
}

else {
cout << "THIS CODE WILL NOT BE GENERATED?!" << endl;
}
}

while(v);
}

The same code with "bool v = true;" instead of "const bool v = true;"
has a size of 9184 byte and runs with no error.

Had the compiler removed the 'else branch' and the 'while cmp
instruction' only looking at the const declaration? If so, why it

It might. Depends on the compiler. Wouldn't surprise me though. Since
v is always true (it's const, remember?), why bother to generate the else
clause, it will never be executed.
can't handle the assignment (with cast) in the modifyConst? It should
be able to understand that what was previously considered a 'safe
const' (regarding to optimizations and expressions reduction) now is
no more a 'safe' one.

Huh? Why should it even attempt to "handle the assignment". You casted
away the constness of an object, and then attempted to modify it. The
compiler has absolutely no obligation to do _anything_ sane with that
code construct.
 
V

Victor Bazarov

Gianguz said:
[..] why it
can't handle the assignment (with cast) in the modifyConst? It should
be able to understand that what was previously considered a 'safe
const' (regarding to optimizations and expressions reduction) now is
no more a 'safe' one.

I think you need to ask in gnu.g++.help or gnu.g++.bugs (if you consider
it a bug), but from the C++ point of view whatever you did (assignment to
a const object by casting away constness) has _undefined_behaviour_ and no
specific requirement is imposed.

V
 
D

David Crocker

Gianguz said:
The following code compiled with gcc version 3.3.4 20040623 (Gentoo
Linux 3.3.4-r1, ssp-3.3.2-2, pie-8.7.6) produce a segmentation fault
and has a size
of 9095 byte on my machine:

#include <iostream>

using namespace std;

const bool v = true;

void modifyConst() {

const bool tmp = v;

const_cast<bool&>(v) = !tmp;

return;
}

int main() {

do {
if (v) {

cout << "FOREVER HERE?!?!" << endl;

modifyConst();
}

else {
cout << "THIS CODE WILL NOT BE GENERATED?!" << endl;
}
}

while(v);
}

The same code with "bool v = true;" instead of "const bool v = true;"
has a size of 9184 byte and runs with no error.

Had the compiler removed the 'else branch' and the 'while cmp
instruction' only looking at the const declaration? If so, why it
can't handle the assignment (with cast) in the modifyConst? It should
be able to understand that what was previously considered a 'safe
const' (regarding to optimizations and expressions reduction) now is
no more a 'safe' one.

Thanks,

Gianguglielmo

It could be that gcc has allocated space for "v" in read-only memory, seeing
that you declared it const. The segmentation fault would then be the
consequence of trying to change it. This is perfectly legal behavior since
the effect of trying to change a "const" item as you are doing is undefined.

David
 
J

jcoffin

Modifying an object that is defined as const gives undefined behavior.
The compiler doesn't have to detect it, doesn't have to diagnose it,
and has no obligation to handle it in any particular fashion.

Bottom line: you've lied to the compiler, and when you do that, it WILL
get its revenge.
 
G

gianguglielmo.calvi

The point is that the compiler is able to put into read-only memory
only const built-in types
initialized to value known at compile time. Any other const allocation
belongs to the same mechanism of non-const ones. So, even if not so
'legal', it is really safe the following:

class Const {
public:
const bool _const;
Const() : _const(false) { }
};

const Const v;

int main() {
bool value = true;
do {
value = !value;
const_cast<bool&>(const_cast<Const&>(v)._const) = value;
}
while(1);
}


Cheers,

Gianguglielmo
 
V

Victor Bazarov

The point is that the compiler is able to put into read-only memory
only const built-in types
initialized to value known at compile time. Any other const allocation
belongs to the same mechanism of non-const ones. So, even if not so
'legal', it is really safe the following:

class Const {
public:
const bool _const;
Const() : _const(false) { }
};

const Const v;

int main() {
bool value = true;
do {
value = !value;
const_cast<bool&>(const_cast<Const&>(v)._const) = value;
}
while(1);
}

Hold on a minute... Are you saying that '::v' in your code is initialised
with something other than a constant value? While it has a "non-trivial"
constructor, what is there to prevent the compiler from figuring out the
intialisation of '::v' at the compile-time? I can't find anything in the
Standard saying that the compiler shall not create such object in
read-only storage if it can. So, pardon me, until proven otherwise, I
will not consider "not legal" "safe".

V
 
G

gianguz

I think you should have to check the following code and the Stroustrup
3d edition at section 5.4 "Constants".
Anyway you are not compelled to trust me or to consider that "legal"
code "safe"! ;)

const bool f(const int x) {

for(int i=0; i<x; i++)

if (x - i > i + i)

return true;

else

return false;

return false;
}

const bool const0 = f(0);

const bool const1 = (const0 && f(const0));

const bool const2 = (false && f(const0));

class Const {

public:

const bool const3;

Const() : const3(true) { }

~Const() { }
};

const Const v;

int main() {

bool value = true;

do {

value = !value;

//1) this is safe
const_cast<bool&>(const0) = value;

//2) this is safe because even if const0=f(0)=false and
f(const0)=f(0)=false compilers doesn't understand that
const_cast<bool&>(const1) = value;

//3) this make the program crash because compilers knows that
const2 = false so it doesn't reserve memory for it that can be later
referred...try to comment it! ;)
const_cast<bool&>(const2) = value;

//4) also this is safe
const_cast<bool&>(const_cast<Const&>(v).const3) = value;
}

while(1);
}
 
D

Dave O'Hearn

gianguz said:
I think you should have to check the following code and the
Stroustrup 3d edition at section 5.4 "Constants".
Anyway you are not compelled to trust me or to consider that
"legal" code "safe"! ;)

I don't know about "safe". I'd say "won't cause a segmentation fault
under gcc's current methods of handling const". gcc only puts a const
in readonly memory if its value can be determined at compile time.
That's a fine thing to understand if you're curious, but it is a fact
about specific implementations of gcc, not about C++.

const_cast is mainly useful for interfacing to old APIs that are not
const correct. For example, strcmp is defined like this,

int strcmp(const char *s1, const char *s2);

But imagine an application has its own case-insensitive strcmp, but
that it is not const correct,

// Case-insensitive strcmp!
// Documentation says it does not modify its arguments.
int str_i_cmp(char *s1, char *s2);

Since it does not modify its arguments, the they should have been
declared const char * but they were not. This is a hassle if you have
to call it with const char * arguments, but since you know the function
does not modify the arguments, you can cast the const away to make the
call.

I can't think of anything else const_cast is good for.
 
G

gianguz

Dave said:
const_cast is mainly useful for interfacing to old APIs that are not
const correct. For example, strcmp is defined like this,

int strcmp(const char *s1, const char *s2);

I partially agree
But imagine an application has its own case-insensitive strcmp, but
that it is not const correct,

// Case-insensitive strcmp!
// Documentation says it does not modify its arguments.
int str_i_cmp(char *s1, char *s2);

Since it does not modify its arguments, the they should have been
declared const char * but they were not. This is a hassle if you have
to call it with const char * arguments, but since you know thedeclare function
does not modify the arguments, you can cast the const away to make the
call.

I can't think of anything else const_cast is good for.

For example you can have a class method const bool foo(const X* ptr)
that does not modify X pointed by ptr. In foo's body you refers to N
const method of the pointed instance but you need only 1 (for instance)
temporary access to a non-const data member of that object instance.
Your function is stricter then the general case needed and safest.

The problem is that i don't think const allocation in read-only depends
on the compiler. Do you know about compilers able to do the following:

const bool f(const int x) {

for(int i=0; i<x; i++)

if (x - i > i + i)

return true;

else
return false;

return false;
}

int main() {

const bool value = f(0);
//at this point a compiler should be able to allocate a compile
//time known const into read-only memory in a dynamical way...mmmm...
const bool tmp = *(new const bool(true));

while(1) {

const_cast<bool&>(value) = !tmp;

const_cast<bool&>(tmp) = value;
}
}

I think that read-only memory can only be allocated during
the program startup, but i need confirmations of that.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top