[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

The differences between the object and the pointer points to object

kailang.deng

12/9/2008 1:17:00 PM

Hello,everybody

I have a program as follows.

class ClassA
{
public:
int buff[1];
virtual void test(void) {cout<<"ClassA::test()"<<endl;}
};

void entry(void)
{
cout<<"Hey,i am here!"<<endl;
}

ClassA Obj1,Obj2,*pObj;

int main()
{
pObj=&Obj2;

//Test group 1
Obj2.test();
pObj->test();

//Obj1.buff[1] covers the pvftable field of Obj2
int vtab=(int)(entry);
Obj1.buff[1]=(int)&vtab;

//Test group 2
Obj2.test();
pObj->test();

return 0;
}
The result is:
ClassA::test()
ClassA::test()
ClassA::test()
Hey,i am here!

Then,it is the point that i am confused.
In my viewpoint,after covering the pvftable field of Obj2,both Obj2
and pObj should invoke the function entry and print "Hey,i am here!".

Then i disassemble the program,it likes as follow
Obj2.test();
00401202 mov ecx,offset Obj2 (0042e168)
00401207 call @ILT+20(ClassA::test) (00401019)
pObj->test();
0040120C mov eax,[pObj (0042e158)]
00401211 mov edx,dword ptr [eax]
:
:
0040121B call dword ptr [edx]

These disassembly codes may have explain the print result.
But can anybody explains the differences between the object and the
pointer points to object?
Thanks a lot!

-Bruce
6 Answers

James Kanze

12/9/2008 2:26:00 PM

0

On Dec 9, 2:17 pm, kailang.d...@gmail.com wrote:

> I have a program as follows.

> class ClassA
> {
> public:
> int buff[1];
> virtual void test(void) {cout<<"ClassA::test()"<<endl;}
> };

> void entry(void)
> {
> cout<<"Hey,i am here!"<<endl;
> }

> ClassA Obj1,Obj2,*pObj;

> int main()
> {
> pObj=&Obj2;

> //Test group 1
> Obj2.test();
> pObj->test();

> //Obj1.buff[1] covers the pvftable field of Obj2
> int vtab=(int)(entry);

I'm not too sure what you thing you're doing in the above.

> Obj1.buff[1]=(int)&vtab;

Nor here (but this is clearly undefined behavior---anything can
happen).

> //Test group 2
> Obj2.test();
> pObj->test();

> return 0;
> }

> The result is:
> ClassA::test()
> ClassA::test()
> ClassA::test()
> Hey,i am here!

> Then,it is the point that i am confused.
> In my viewpoint,after covering the pvftable field of Obj2,both
> Obj2 and pObj should invoke the function entry and print
> "Hey,i am here!".

In my viewpoint, you have undefined behavior. Basically, you
lied to the compiler, and it's getting its revenge.

> Then i disassemble the program,it likes as follow
> Obj2.test();
> 00401202 mov ecx,offset Obj2 (0042e168)
> 00401207 call @ILT+20(ClassA::test) (00401019)
> pObj->test();
> 0040120C mov eax,[pObj (0042e158)]
> 00401211 mov edx,dword ptr [eax]
> :
> :
> 0040121B call dword ptr [edx]

> These disassembly codes may have explain the print result.
> But can anybody explains the differences between the object
> and the pointer points to object?

The compiler has a better chance to optimize when pointers
aren't involved. Since the compiler knows the actual type of
the object, it doesn't bother with using the vptr (which depends
*only* on the type of the object, and cannot change) when
calling a virtual function on the object.

Turn up the optimization level, and "Hey, I am here" might
disappear completely.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

jason.cipriani@gmail.com

12/9/2008 4:06:00 PM

0

On Dec 9, 8:17 am, kailang.d...@gmail.com wrote:
> Hello,everybody
>
> I have a program as follows.
>
> class ClassA
> {
> public:
>         int buff[1];
>         virtual void test(void) {cout<<"ClassA::test()"<<endl;}
>
> };
>
> void entry(void)
> {
>         cout<<"Hey,i am here!"<<endl;
>
> }
>
> ClassA Obj1,Obj2,*pObj;
>
> int main()
> {
>         pObj=&Obj2;
>
>         //Test group 1
>         Obj2.test();
>         pObj->test();
>
>         //Obj1.buff[1] covers the pvftable field of Obj2
>         int vtab=(int)(entry);

You should use reinterpret_cast<>, and you have to be able to
guarantee that an int is large enough to hold a function pointer, or
this conversion is undefined.

>         Obj1.buff[1]=(int)&vtab;

You can't rely on the virtual table having a specific layout, or being
in a specific place, or holding certain types of data (and certainly
not on it being able to use a function pointer cast to an int), or the
layout of global variables in memory being somehow related to the
order you've declared them in.

It appears that you are attempting to do this:

ClassA Obj1, Obj2;

In hopes that Obj2 will always come after Obj1 in memory, and that
Obj2's vtable entries come immediately after the data for Obj1, and
that by accessing past the end of Obj1's data array, you're
overwriting the appropriate vtable entry with valid data. All of that
is *entirely* outside the scope of C++, and the program is undefined.
Any weird behavior you see is arguably off-topic here.

You'd be better served by doing whatever it is you're trying to do
using normal, well-defined concepts like inheritance, or function
pointers. This is one way to do what you're trying to do, with
inheritance:

class ClassA {
public:
virtual void test () {cout<<"ClassA::test()"<<endl;}
};

class ClassB : public ClassA {
public:
void test () {cout<<"Hey,i am here!"<<endl}
};

ClassA Obj1;
ClassB Obj2;

int main () {
Obj1.test();
Obj2.test();
}


Using a function pointer can give you the same behavior as the
intended behavior of your original program (I did not test or compile
this):

void default_test () { ... }
void entry () { ... }

class ClassA {
public:
void (* test) ();
ClassA () : test(default_test) { }
};

void elsewhere () {
ClassA obj;
obj.test = entry;
obj.test();
}


Using a functor would give you more flexibility. There are many other
ways to accomplish the same sort of thing as well, all that *are*
defined by C++.

Why are you trying to do it this way, anyways?

Jason

>
>         //Test group 2
>         Obj2.test();
>         pObj->test();
>
>         return 0;}
>
> The result is:
> ClassA::test()
> ClassA::test()
> ClassA::test()
> Hey,i am here!
>
> Then,it is the point that i am confused.
> In my viewpoint,after covering the pvftable field of Obj2,both Obj2
> and pObj should invoke the function entry and print "Hey,i am here!".
>
> Then i disassemble the program,it likes as follow
> Obj2.test();
> 00401202   mov         ecx,offset Obj2 (0042e168)
> 00401207   call        @ILT+20(ClassA::test) (00401019)
> pObj->test();
> 0040120C   mov         eax,[pObj (0042e158)]
> 00401211   mov         edx,dword ptr [eax]
>                        :
>                        :
> 0040121B   call        dword ptr [edx]
>
> These disassembly codes may have explain the print result.
> But can anybody explains the differences between the object and the
> pointer points to object?
> Thanks a lot!
>
> -Bruce

kailang.deng

12/10/2008 6:11:00 AM

0

On Dec 9, 10:26 pm, James Kanze <james.ka...@gmail.com> wrote:
> On Dec 9, 2:17 pm, kailang.d...@gmail.com wrote:
>
>
>
>
>
> > I have a program as follows.
> > class ClassA
> > {
> > public:
> >         int buff[1];
> >         virtual void test(void) {cout<<"ClassA::test()"<<endl;}
> > };
> > void entry(void)
> > {
> >         cout<<"Hey,i am here!"<<endl;
> > }
> > ClassA Obj1,Obj2,*pObj;
> > int main()
> > {
> >         pObj=&Obj2;
> >         //Test group 1
> >         Obj2.test();
> >         pObj->test();
> >         //Obj1.buff[1] covers the pvftable field of Obj2
> >         int vtab=(int)(entry);
>
> I'm not too sure what you thing you're doing in the above.
>
> >         Obj1.buff[1]=(int)&vtab;
>
> Nor here (but this is clearly undefined behavior---anything can
> happen).

I intended to overwrite the pvftable entry of Obj2 by let the buff
array be out of bound,because Obj2 comes after Obj1 in the
memory.Finally,the vpftable of Obj2 will be covered by the address of
entry function.

>

> >         //Test group 2
> >         Obj2.test();
> >         pObj->test();
> >         return 0;
> > }
> > The result is:
> > ClassA::test()
> > ClassA::test()
> > ClassA::test()
> > Hey,i am here!
> > Then,it is the point that i am confused.
> > In my viewpoint,after covering the pvftable field of Obj2,both
> > Obj2 and pObj should invoke the function entry and print
> > "Hey,i am here!".
>
> In my viewpoint, you have undefined behavior.  Basically, you
> lied to the compiler, and it's getting its revenge.
>
> > Then i disassemble the program,it likes as follow
> > Obj2.test();
> > 00401202   mov         ecx,offset Obj2 (0042e168)
> > 00401207   call        @ILT+20(ClassA::test) (00401019)
> > pObj->test();
> > 0040120C   mov         eax,[pObj (0042e158)]
> > 00401211   mov         edx,dword ptr [eax]
> >                        :
> >                        :
> > 0040121B   call        dword ptr [edx]
> > These disassembly codes may have explain the print result.
> > But can anybody explains the differences between the object
> > and the pointer points to object?
>
> The compiler has a better chance to optimize when pointers
> aren't involved.  Since the compiler knows the actual type of
> the object, it doesn't bother with using the vptr (which depends
> *only* on the type of the object, and cannot change) when
> calling a virtual function on the object.
>

These explainations above have resolved my question primely.Thanks
very much!

> Turn up the optimization level, and "Hey, I am here" might
> disappear completely.
>
I tried to change the optimization level to Minimize Size or Maximize
Speed.But "Hey, I am here" still appear.Is my optimization level
setting error or other reasons?
Great appreciations for your detailed help!Thank you!
> --
> James Kanze (GABI Software)             email:james.ka...@gmail.com
> Conseils en informatique orientée objet/
>                    Beratung in objektorientierter Datenverarbeitung
> 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34- Hide quoted text -
>
> - Show quoted text -

kailang.deng

12/10/2008 6:36:00 AM

0

On Dec 10, 12:05 am, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.com> wrote:
> On Dec 9, 8:17 am, kailang.d...@gmail.com wrote:
>
>
>
>
>
> > Hello,everybody
>
> > I have a program as follows.
>
> > class ClassA
> > {
> > public:
> >         int buff[1];
> >         virtual void test(void) {cout<<"ClassA::test()"<<endl;}
>
> > };
>
> > void entry(void)
> > {
> >         cout<<"Hey,i am here!"<<endl;
>
> > }
>
> > ClassA Obj1,Obj2,*pObj;
>
> > int main()
> > {
> >         pObj=&Obj2;
>
> >         //Test group 1
> >         Obj2.test();
> >         pObj->test();
>
> >         //Obj1.buff[1] covers the pvftable field of Obj2
> >         int vtab=(int)(entry);
>
> You should use reinterpret_cast<>, and you have to be able to
> guarantee that an int is large enough to hold a function pointer, or
> this conversion is undefined.
>

Using reinterpret_cast<> is a good suggestion.The size of a function
pointer and the size of int type are both 4 bytes in MSVC.So,i think
that an int can hold the pointer.

> >         Obj1.buff[1]=(int)&vtab;
>
> You can't rely on the virtual table having a specific layout, or being
> in a specific place, or holding certain types of data (and certainly
> not on it being able to use a function pointer cast to an int), or the
> layout of global variables in memory being somehow related to the
> order you've declared them in.
>
> It appears that you are attempting to do this:
>
>   ClassA Obj1, Obj2;
>
> In hopes that Obj2 will always come after Obj1 in memory, and that
> Obj2's vtable entries come immediately after the data for Obj1, and
> that by accessing past the end of Obj1's data array, you're
> overwriting the appropriate vtable entry with valid data. All of that
> is *entirely* outside the scope of C++, and the program is undefined.
> Any weird behavior you see is arguably off-topic here.
>
> You'd be better served by doing whatever it is you're trying to do
> using normal, well-defined concepts like inheritance, or function
> pointers. This is one way to do what you're trying to do, with
> inheritance:
>
> class ClassA {
> public:
>   virtual void test () {cout<<"ClassA::test()"<<endl;}
>
> };
>
> class ClassB : public ClassA {
> public:
>   void test () {cout<<"Hey,i am here!"<<endl}
>
> };
>
> ClassA Obj1;
> ClassB Obj2;
>
> int main () {
>   Obj1.test();
>   Obj2.test();
>
> }
>
> Using a function pointer can give you the same behavior as the
> intended behavior of your original program (I did not test or compile
> this):
>
> void default_test () { ... }
> void entry () { ... }
>
> class ClassA {
> public:
>   void (* test) ();
>   ClassA () : test(default_test) { }
>
> };
>
> void elsewhere () {
>   ClassA obj;
>   obj.test = entry;
>   obj.test();
>
> }
>
> Using a functor would give you more flexibility. There are many other
> ways to accomplish the same sort of thing as well, all that *are*
> defined by C++.
>
Thanks Jason for the two good suggestions especially using a function
pointer from which I learn a lot. I will consider it in the later.

> Why are you trying to do it this way, anyways?
I just want to explore the inner of C++ VPTR by smashing it. But i
don't know the way isn't defined by C++.
Finally, thanks a lot for your detailed answers and the suggestions.
Regard~

-Bruce
>
> Jason
>
>
>
>
>
> >         //Test group 2
> >         Obj2.test();
> >         pObj->test();
>
> >         return 0;}
>
> > The result is:
> > ClassA::test()
> > ClassA::test()
> > ClassA::test()
> > Hey,i am here!
>
> > Then,it is the point that i am confused.
> > In my viewpoint,after covering the pvftable field of Obj2,both Obj2
> > and pObj should invoke the function entry and print "Hey,i am here!".
>
> > Then i disassemble the program,it likes as follow
> > Obj2.test();
> > 00401202   mov         ecx,offset Obj2 (0042e168)
> > 00401207   call        @ILT+20(ClassA::test) (00401019)
> > pObj->test();
> > 0040120C   mov         eax,[pObj (0042e158)]
> > 00401211   mov         edx,dword ptr [eax]
> >                        :
> >                        :
> > 0040121B   call        dword ptr [edx]
>
> > These disassembly codes may have explain the print result.
> > But can anybody explains the differences between the object and the
> > pointer points to object?
> > Thanks a lot!
>
> > -Bruce- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -

James Kanze

12/10/2008 9:49:00 AM

0

On Dec 10, 7:11 am, Bruclee <kailang.d...@gmail.com> wrote:
> On Dec 9, 10:26 pm, James Kanze <james.ka...@gmail.com> wrote:
> > On Dec 9, 2:17 pm, kailang.d...@gmail.com wrote:

> > > I have a program as follows.
> > > class ClassA
> > > {
> > > public:
> > > int buff[1];
> > > virtual void test(void) {cout<<"ClassA::test()"<<endl;}
> > > };
> > > void entry(void)
> > > {
> > > cout<<"Hey,i am here!"<<endl;
> > > }
> > > ClassA Obj1,Obj2,*pObj;
> > > int main()
> > > {
> > > pObj=&Obj2;
> > > //Test group 1
> > > Obj2.test();
> > > pObj->test();
> > > //Obj1.buff[1] covers the pvftable field of Obj2
> > > int vtab=(int)(entry);

> > I'm not too sure what you thing you're doing in the above.

> > > Obj1.buff[1]=(int)&vtab;

> > Nor here (but this is clearly undefined behavior---anything
> > can happen).

> I intended to overwrite the pvftable entry of Obj2 by let the
> buff array be out of bound,because Obj2 comes after Obj1 in
> the memory.Finally,the vpftable of Obj2 will be covered by the
> address of entry function.

I understand that. I was being slightly ironic---just to insist
on the fact that this really doesn't have any meaning. (For
starters, you're not guaranteed that Obj1 and Obj2 are adjacent,
or in that order, in memory.)

What you're doing depend very, very much on internal details of
the compiler. I think you knew that at least partially, but I
wasn't sure just how much, since you seemed surprised at the
output.

[...]
> > Turn up the optimization level, and "Hey, I am here" might
> > disappear completely.

> I tried to change the optimization level to Minimize Size or
> Maximize Speed.But "Hey, I am here" still appear.Is my
> optimization level setting error or other reasons?

I said "might". It depends on the optimizer, but it's entirely
within the capabilities of modern optimizers to determine that
your pointer never points to anything but a ClassA, and so not
generate the code to determine the type dynamcally.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

kailang.deng

12/10/2008 12:29:00 PM

0

On Dec 10, 5:49 pm, James Kanze <james.ka...@gmail.com> wrote:
> On Dec 10, 7:11 am, Bruclee <kailang.d...@gmail.com> wrote:
>
>
>
>
>
> > On Dec 9, 10:26 pm, James Kanze <james.ka...@gmail.com> wrote:
> > > On Dec 9, 2:17 pm, kailang.d...@gmail.com wrote:
> > > > I have a program as follows.
> > > > class ClassA
> > > > {
> > > > public:
> > > >         int buff[1];
> > > >         virtual void test(void) {cout<<"ClassA::test()"<<endl;}
> > > > };
> > > > void entry(void)
> > > > {
> > > >         cout<<"Hey,i am here!"<<endl;
> > > > }
> > > > ClassA Obj1,Obj2,*pObj;
> > > > int main()
> > > > {
> > > >         pObj=&Obj2;
> > > >         //Test group 1
> > > >         Obj2.test();
> > > >         pObj->test();
> > > >         //Obj1.buff[1] covers the pvftable field of Obj2
> > > >         int vtab=(int)(entry);
> > > I'm not too sure what you thing you're doing in the above.
> > > >         Obj1.buff[1]=(int)&vtab;
> > > Nor here (but this is clearly undefined behavior---anything
> > > can happen).
> > I intended to overwrite the pvftable entry of Obj2 by let the
> > buff array be out of bound,because Obj2 comes after Obj1 in
> > the memory.Finally,the vpftable of Obj2 will be covered by the
> > address of entry function.
>
> I understand that.  I was being slightly ironic---just to insist
> on the fact that this really doesn't have any meaning.  (For
> starters, you're not guaranteed that Obj1 and Obj2 are adjacent,
> or in that order, in memory.)
>
> What you're doing depend very, very much on internal details of
> the compiler.  I think you knew that at least partially, but I
> wasn't sure just how much, since you seemed surprised at the
> output.
>
>     [...]

I noticed some difference between the different compiler.Under
windows,Visual C++6.0 places pvftable right
the begining of the object while C++ GNU place the pvftable at the end
of
the object and Obj1 and Obj2 are adjacent in memory under windows.
Without considering portability,I want to find if we can do some
crack(conduct the program to invoke the function designated by
ourselves
instead of the virtual function issued by program or manufacturer) by
overwrite the pvftable of the object under MS VC6.0 since we use a lot
of
virtual functions provided by class library or manufacturer through
inheritance.
Since the simple idea above, i do the test to check the safty of class
with
virtual functions.

Thank you for your enthusiasm help!
-Bruce
>
> > > Turn up the optimization level, and "Hey, I am here" might
> > > disappear completely.
> > I tried to change the optimization level to Minimize Size or
> > Maximize Speed.But "Hey, I am here" still appear.Is my
> > optimization level setting error or other reasons?
>
> I said "might".  It depends on the optimizer, but it's entirely
> within the capabilities of modern optimizers to determine that
> your pointer never points to anything but a ClassA, and so not
> generate the code to determine the type dynamcally.
>
> --
> James Kanze (GABI Software)             email:james.ka...@gmail.com
> Conseils en informatique orientée objet/
>                    Beratung in objektorientierter Datenverarbeitung
> 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34- Hide quoted text -
>
> - Show quoted text -