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).