public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/14827] New: Run time error, breaking of type info and static casts
@ 2004-04-02 22:57 Igor dot Smirnov at cern dot ch
2004-04-02 23:15 ` [Bug c++/14827] " pinskia at gcc dot gnu dot org
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Igor dot Smirnov at cern dot ch @ 2004-04-02 22:57 UTC (permalink / raw)
To: gcc-bugs
Hello.
Developing very large program I met a problem with covariant return types,
which I tried to bypass with void return types, but did not achieve success due
to a bug in g++. Fortunately, I managed to reproduce the most of the effects in
very little example, which I am sending you. But please be aware that similar
problems perhaps appear at different class configurations, not only at this one.
(I know because in my real program configuration is little bit different).
I have tested this example at two different sites with two compilers (both - PC
Pentium 4 with RedHat):
First:
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man
--infodir=/usr/share/info --enable-shared --enable-threads=posix
--disable-checking --host=i386-redhat-linux --with-system-zlib --enable-__cxa_atexit
Thread model: posix
gcc version 3.2 20020903 (Red Hat Linux 8.0 3.2-7)
Second:
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-113)
The output of the both cases is the case:
SuperDerived::print: Hello
SuperDerived::fun: Hello
SuperDerived::fun: Hello
SuperDerived::fun: Hello
Here only the first line is correct. Three the others are not.
In all the cases one should expect the reply from function print() like
occured in the first line. But the type information is somehow broken
during the static casts, which are expected to affect the type assigned by
compiler to the pointer, but not the type of the object, by my understanding.
This violation results in involving different function of the class. In my real
program this results in skipping the print function at all and in segmentation
fault a few lines later.
Some comments on how static casts are extected to function can be obtained in B.
Stroustrup, The C++ Programming Language, Special edition, Addison-Weley, p. 413.
I would appreciate if you let me know whether this problem has already been
corrected in newer release of g++, or not, or can it be corrected at all. Are
there ways to bypass it. By my opinition this is a real and very serious
problem. Thank you.
Regards
Igor Smirnov
The code:
#include <iostream.h>
class Base1
{public:
int j;
virtual void print(void) { cout<<"Base1::print: Hello\n";}
};
class Base2
{public:
int k;
virtual void fun(void) = 0;
virtual void print(void) { cout<<"Base2::print: Hello\n";}
};
class Derived: public Base1
{public:
int l;
virtual void print(void) { cout<<"Derived::print: Hello\n";}
};
class SuperDerived: public Base2, public Derived
{public:
int m;
virtual void fun(void) { cout<<"SuperDerived::fun: Hello\n";}
virtual void print(void) { cout<<"SuperDerived::print: Hello\n";}
};
int main(void)
{
SuperDerived sd;
Derived* ad = new SuperDerived(sd);
ad->print();
ad = ( Derived* ) ( (void*) new SuperDerived(sd) );
ad->print();
ad = static_cast< Derived* > ( (void*) new SuperDerived(sd) );
ad->print();
ad = static_cast< Derived* >
( static_cast< void* > ( new SuperDerived(sd) ) );
ad->print();
}
--
Summary: Run time error, breaking of type info and static casts
Product: gcc
Version: 3.2
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: c++
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: Igor dot Smirnov at cern dot ch
CC: gcc-bugs at gcc dot gnu dot org
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14827
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/14827] Run time error, breaking of type info and static casts
2004-04-02 22:57 [Bug c++/14827] New: Run time error, breaking of type info and static casts Igor dot Smirnov at cern dot ch
@ 2004-04-02 23:15 ` pinskia at gcc dot gnu dot org
2004-04-02 23:30 ` bangerth at dealii dot org
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: pinskia at gcc dot gnu dot org @ 2004-04-02 23:15 UTC (permalink / raw)
To: gcc-bugs
------- Additional Comments From pinskia at gcc dot gnu dot org 2004-04-02 23:15 -------
I think this is undefined behavior but I do not know.
A work around for this testcase is to swap the order of the base classes of the super most class:
class SuperDerived: public Derived, public Base2
--
What |Removed |Added
----------------------------------------------------------------------------
Keywords| |wrong-code
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14827
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/14827] Run time error, breaking of type info and static casts
2004-04-02 22:57 [Bug c++/14827] New: Run time error, breaking of type info and static casts Igor dot Smirnov at cern dot ch
2004-04-02 23:15 ` [Bug c++/14827] " pinskia at gcc dot gnu dot org
@ 2004-04-02 23:30 ` bangerth at dealii dot org
2004-04-03 17:21 ` giovannibajo at libero dot it
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: bangerth at dealii dot org @ 2004-04-02 23:30 UTC (permalink / raw)
To: gcc-bugs
------- Additional Comments From bangerth at dealii dot org 2004-04-02 23:30 -------
I can confirm this with all compiler up to and including mainline. And
also with Intel's icc7.
However, your code is invalid. When you cast to void*, the compiler
loses track of where the Derived part of your SuperDerived object
resides. Then, when you cast back from void*, the compiler has to
assume that this cast does not need any pointer adjustment. There is
simply no way the compiler can do what you want in view of this. You
can't cast to void* and expect the compiler to work with this correctly.
W.
--
What |Removed |Added
----------------------------------------------------------------------------
Status|UNCONFIRMED |RESOLVED
Resolution| |INVALID
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14827
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/14827] Run time error, breaking of type info and static casts
2004-04-02 22:57 [Bug c++/14827] New: Run time error, breaking of type info and static casts Igor dot Smirnov at cern dot ch
2004-04-02 23:15 ` [Bug c++/14827] " pinskia at gcc dot gnu dot org
2004-04-02 23:30 ` bangerth at dealii dot org
@ 2004-04-03 17:21 ` giovannibajo at libero dot it
2004-04-05 8:14 ` Igor dot Smirnov at cern dot ch
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: giovannibajo at libero dot it @ 2004-04-03 17:21 UTC (permalink / raw)
To: gcc-bugs
------- Additional Comments From giovannibajo at libero dot it 2004-04-03 17:20 -------
Yes. In legalese, the standard says that if you cast a pointer to an object to
a pointer to void, the only valid thing you can do with that is casting it back
to the same object type and use it. Otherwise, you hit undefined behaviour.
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14827
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/14827] Run time error, breaking of type info and static casts
2004-04-02 22:57 [Bug c++/14827] New: Run time error, breaking of type info and static casts Igor dot Smirnov at cern dot ch
` (2 preceding siblings ...)
2004-04-03 17:21 ` giovannibajo at libero dot it
@ 2004-04-05 8:14 ` Igor dot Smirnov at cern dot ch
2004-04-05 8:36 ` Igor dot Smirnov at cern dot ch
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Igor dot Smirnov at cern dot ch @ 2004-04-05 8:14 UTC (permalink / raw)
To: gcc-bugs
------- Additional Comments From Igor dot Smirnov at cern dot ch 2004-04-05 08:14 -------
Hello,
I am quiote susprised by this letter. May I ask a few questions.
(In reply to comment #2)
> I can confirm this with all compiler up to and including mainline. And
> also with Intel's icc7.
>
> However, your code is invalid. When you cast to void*, the compiler
> loses track of where the Derived part of your SuperDerived object
> resides.
What does it mean? Why the Derived part should be located somewhere else?
I thought and think that this is correct that additions of SuperDerived
just follow components of Derived.
> Then, when you cast back from void*, the compiler has to
> assume that this cast does not need any pointer adjustment.
Again, this is not clear, but this correlates with the first question.
I thought (may be naively) that the convertion of pointer should affect
neither of binary representation of object, nor the pointer itself.
> There is
> simply no way the compiler can do what you want in view of this. You
> can't cast to void* and expect the compiler to work with this correctly.
By my understanding it can be done trivially, so surely there is the way. Just
not touch referred object, and that's all.
Let me reprint here citation from the mentioned book of Stroustrup
(B.Stroustrup, The C++ Programming Language, Special edition, Addison-Weley, p.
413):
"The compiler cannot assume anything about the memory pointed to by a void*.
This implies that dynamic_cast - which must look into an object to determine its
type - cannot cast from a void*. For that, a static_cast is needed. For example:
Radio* f(void* p)
{
Storable* ps = static_cast<Storable*>(p); // trust the programmer
return dynamic_cast<Radio*>(ps);
}
" (finish of citation)
And looking at the previous example just at the same page in this boook we can
read the comment: "Storable is virtual base of Radio". So, it looks like that
conversion of pointer to void* (may be implicit at calling this function, or
explicit, but this should not make differencce, do you agree?) by the opinion of
the creator of this language should not destroy the object and its type and
should allow later correct static casts of pointer to the base type. This is
valid even for virtual base class. Could you comment this, please?
Regards
Igor Smirnov
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14827
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/14827] Run time error, breaking of type info and static casts
2004-04-02 22:57 [Bug c++/14827] New: Run time error, breaking of type info and static casts Igor dot Smirnov at cern dot ch
` (3 preceding siblings ...)
2004-04-05 8:14 ` Igor dot Smirnov at cern dot ch
@ 2004-04-05 8:36 ` Igor dot Smirnov at cern dot ch
2004-04-05 13:34 ` bangerth at dealii dot org
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Igor dot Smirnov at cern dot ch @ 2004-04-05 8:36 UTC (permalink / raw)
To: gcc-bugs
------- Additional Comments From Igor dot Smirnov at cern dot ch 2004-04-05 08:36 -------
(In reply to comment #4)
Hello again,
Let me annul this my connent. I understood what you mean. When you implement
covariant return types? Please do this quicklier.
Igor
> Hello,
>
> I am quiote susprised by this letter. May I ask a few questions.
>
> (In reply to comment #2)
> > I can confirm this with all compiler up to and including mainline. And
> > also with Intel's icc7.
> >
> > However, your code is invalid. When you cast to void*, the compiler
> > loses track of where the Derived part of your SuperDerived object
> > resides.
>
> What does it mean? Why the Derived part should be located somewhere else?
> I thought and think that this is correct that additions of SuperDerived
> just follow components of Derived.
>
> > Then, when you cast back from void*, the compiler has to
> > assume that this cast does not need any pointer adjustment.
>
> Again, this is not clear, but this correlates with the first question.
> I thought (may be naively) that the convertion of pointer should affect
> neither of binary representation of object, nor the pointer itself.
>
>
> > There is
> > simply no way the compiler can do what you want in view of this. You
> > can't cast to void* and expect the compiler to work with this correctly.
>
> By my understanding it can be done trivially, so surely there is the way. Just
> not touch referred object, and that's all.
>
> Let me reprint here citation from the mentioned book of Stroustrup
> (B.Stroustrup, The C++ Programming Language, Special edition, Addison-Weley, p.
> 413):
>
> "The compiler cannot assume anything about the memory pointed to by a void*.
> This implies that dynamic_cast - which must look into an object to determine its
> type - cannot cast from a void*. For that, a static_cast is needed. For example:
>
> Radio* f(void* p)
> {
> Storable* ps = static_cast<Storable*>(p); // trust the programmer
> return dynamic_cast<Radio*>(ps);
> }
> " (finish of citation)
>
> And looking at the previous example just at the same page in this boook we can
> read the comment: "Storable is virtual base of Radio". So, it looks like that
> conversion of pointer to void* (may be implicit at calling this function, or
> explicit, but this should not make differencce, do you agree?) by the opinion of
> the creator of this language should not destroy the object and its type and
> should allow later correct static casts of pointer to the base type. This is
> valid even for virtual base class. Could you comment this, please?
>
> Regards
> Igor Smirnov
>
>
>
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14827
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/14827] Run time error, breaking of type info and static casts
2004-04-02 22:57 [Bug c++/14827] New: Run time error, breaking of type info and static casts Igor dot Smirnov at cern dot ch
` (4 preceding siblings ...)
2004-04-05 8:36 ` Igor dot Smirnov at cern dot ch
@ 2004-04-05 13:34 ` bangerth at dealii dot org
2004-04-05 15:36 ` giovannibajo at libero dot it
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: bangerth at dealii dot org @ 2004-04-05 13:34 UTC (permalink / raw)
To: gcc-bugs
------- Additional Comments From bangerth at dealii dot org 2004-04-05 13:34 -------
Covariant return types are implemented in the upcoming 3.4. However,
they have nothing to do with your problem.
Really, you have to understand that a cast can change the representation
of a pointer. One example is when you have a pointer to a derived class
which has two base classes. Casting to one of them must change the
pointer, since the two base classes cannot be at the same memory
location. This is also the reason for the thing Giovanni quotet: when
you cast to void*, the _only_ thing that you can do with this pointer
is to cast it back to the _exact same_ type. You did not do that, so that's
where your error lies.
Please read up on this somewhere.
W.
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14827
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/14827] Run time error, breaking of type info and static casts
2004-04-02 22:57 [Bug c++/14827] New: Run time error, breaking of type info and static casts Igor dot Smirnov at cern dot ch
` (5 preceding siblings ...)
2004-04-05 13:34 ` bangerth at dealii dot org
@ 2004-04-05 15:36 ` giovannibajo at libero dot it
2004-04-06 8:41 ` Igor dot Smirnov at cern dot ch
2004-04-06 10:28 ` giovannibajo at libero dot it
8 siblings, 0 replies; 10+ messages in thread
From: giovannibajo at libero dot it @ 2004-04-05 15:36 UTC (permalink / raw)
To: gcc-bugs
------- Additional Comments From giovannibajo at libero dot it 2004-04-05 15:36 -------
> "The compiler cannot assume anything about the memory pointed to by a void*.
> This implies that dynamic_cast - which must look into an object to determine
its
> type - cannot cast from a void*. For that, a static_cast is needed. For
example:
> Radio* f(void* p)
> {
> Storable* ps = static_cast<Storable*>(p); // trust the programmer
> return dynamic_cast<Radio*>(ps);
> }
> " (finish of citation)
> And looking at the previous example just at the same page in this boook we can
> read the comment: "Storable is virtual base of Radio". So, it looks like that
> conversion of pointer to void* (may be implicit at calling this function, or
> explicit, but this should not make differencce, do you agree?) by the opinion
of
> the creator of this language should not destroy the object and its type and
> should allow later correct static casts of pointer to the base type. This is
> valid even for virtual base class. Could you comment this, please?
You're still wrong, and you are trying to make your book say something it does
not. If you look carefully at the example you posted from the book, you will
see that the cast chain is like this: Storable* -> void* -> Storable* ->
Radio*. In your code, you do like this: SuperDerived* -> void* -> Derived*. You
cannot do this.
The book explains you why: "The compiler cannot assume anything about the
memory pointed to by a void*.". The compiler will have to trust the programmer
(as the comment in the example says) and blindly convert the pointer back to
its *ORIGINAL* type (the type it had before it was casted to void*).
Whether you understand the technical problem or not is insignificant. Both the
standard and C++PL explain you that if you have a void* the only sensible thing
you can do is casting it back to its original type. If you got a void* from a
SuperDerived*, you cannot cast it to Derived*. This is wrong: the standard says
it is undefined behaviour, and you get it. You MUST cast it back to a
SuperDerived before doing anything else.
This would work:
static_cast<Derived*> (static_cast<SuperDerived*> (static_cast<void*> (new
SuperDerived()))).
Also, if you cast it to a Derived* BEFORE casting to void*, you then must cast
it to Derived* again. For instance:
SuperDerived* -> Derived* -> void* -> SuperDerived* = WRONG
SuperDerived* -> Derived* -> void* -> Derived* -> SuperDerived* = CORRECT
--
What |Removed |Added
----------------------------------------------------------------------------
CC| |giovannibajo at libero dot
| |it
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14827
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/14827] Run time error, breaking of type info and static casts
2004-04-02 22:57 [Bug c++/14827] New: Run time error, breaking of type info and static casts Igor dot Smirnov at cern dot ch
` (6 preceding siblings ...)
2004-04-05 15:36 ` giovannibajo at libero dot it
@ 2004-04-06 8:41 ` Igor dot Smirnov at cern dot ch
2004-04-06 10:28 ` giovannibajo at libero dot it
8 siblings, 0 replies; 10+ messages in thread
From: Igor dot Smirnov at cern dot ch @ 2004-04-06 8:41 UTC (permalink / raw)
To: gcc-bugs
------- Additional Comments From Igor dot Smirnov at cern dot ch 2004-04-06 08:40 -------
Subject: Re: Run time error, breaking of type info and static
casts
On 5 Apr 2004, giovannibajo at libero dot it wrote:
>
> ------- Additional Comments From giovannibajo at libero dot it 2004-04-05 15:36 -------
> > "The compiler cannot assume anything about the memory pointed to by a void*.
> > This implies that dynamic_cast - which must look into an object to determine
> its
> > type - cannot cast from a void*. For that, a static_cast is needed. For
> example:
> > Radio* f(void* p)
> > {
> > Storable* ps = static_cast<Storable*>(p); // trust the programmer
> > return dynamic_cast<Radio*>(ps);
> > }
> > " (finish of citation)
>
> > And looking at the previous example just at the same page in this boook we can
> > read the comment: "Storable is virtual base of Radio". So, it looks like that
> > conversion of pointer to void* (may be implicit at calling this function, or
> > explicit, but this should not make differencce, do you agree?) by the opinion
> of
> > the creator of this language should not destroy the object and its type and
> > should allow later correct static casts of pointer to the base type. This is
> > valid even for virtual base class. Could you comment this, please?
>
> You're still wrong, and you are trying to make your book say something it does
> not. If you look carefully at the example you posted from the book, you will
> see that the cast chain is like this: Storable* -> void* -> Storable* ->
> Radio*.
No, there is no such cast chain defined in the book. I looked carefully.
In fact there is no any explicit statement about the way of convertion of
the pointer Radio* into void*, which is assumed before the call of
Radio* f(void* p). So it might be with intermediate Storable*, and equally
might be direct Radio* -> void*.
> The book explains you why: "The compiler cannot assume anything about the
> memory pointed to by a void*.". The compiler will have to trust the programmer
> (as the comment in the example says) and blindly convert the pointer back to
> its *ORIGINAL* type (the type it had before it was casted to void*).
The citation is correct. But your comment is not. The book does not say
this.
>
> Whether you understand the technical problem or not is insignificant. Both the
> standard and C++PL explain you that if you have a void* the only sensible thing
> you can do is casting it back to its original type.
Here I have different approach and estimate of significant things, but I
don't understand, what you mean by "C++PL"? The book of Stroustrup? But I
have not seen this in it. May be I missed it, it is too big.
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14827
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/14827] Run time error, breaking of type info and static casts
2004-04-02 22:57 [Bug c++/14827] New: Run time error, breaking of type info and static casts Igor dot Smirnov at cern dot ch
` (7 preceding siblings ...)
2004-04-06 8:41 ` Igor dot Smirnov at cern dot ch
@ 2004-04-06 10:28 ` giovannibajo at libero dot it
8 siblings, 0 replies; 10+ messages in thread
From: giovannibajo at libero dot it @ 2004-04-06 10:28 UTC (permalink / raw)
To: gcc-bugs
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1011 bytes --]
------- Additional Comments From giovannibajo at libero dot it 2004-04-06 10:27 -------
Subject: Re: Run time error, breaking of type info and static casts
Igor,
I am sure Stroustrup explains it somewhere, maybe with different wording. I'll
cite you the ISO/ANSI C++ standard ([expr.static.cast]/4): "Any expression can
be explicitly converted to type cv void. The expression value is discarded."
When it says that the value is discarded, it means that the expression does not
yield a meaningful value anymore. Later, in paragraph 10, it says: " An rvalue
of type pointer to cv void can be explicitly converted to a pointer to object
type. A value of type pointer to object converted to pointer to cv void and
back to the original pointer type will have its original value.". As you can
see, the only way to get back the original value is to convert it back to the
original pointer type.
I hope this is clear enough.
Giovanni Bajo
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14827
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2004-04-06 10:28 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-04-02 22:57 [Bug c++/14827] New: Run time error, breaking of type info and static casts Igor dot Smirnov at cern dot ch
2004-04-02 23:15 ` [Bug c++/14827] " pinskia at gcc dot gnu dot org
2004-04-02 23:30 ` bangerth at dealii dot org
2004-04-03 17:21 ` giovannibajo at libero dot it
2004-04-05 8:14 ` Igor dot Smirnov at cern dot ch
2004-04-05 8:36 ` Igor dot Smirnov at cern dot ch
2004-04-05 13:34 ` bangerth at dealii dot org
2004-04-05 15:36 ` giovannibajo at libero dot it
2004-04-06 8:41 ` Igor dot Smirnov at cern dot ch
2004-04-06 10:28 ` giovannibajo at libero dot it
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).