The differences between the object and the pointer points to object

K

kailang.deng

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
 
J

James Kanze

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

jason.cipriani

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
 
B

Bruclee

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!
 
B

Bruclee

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 -
 
J

James Kanze

On Dec 9, 2:17 pm, (e-mail address removed) 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 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.
 
B

Bruclee

On Dec 9, 2:17 pm, (e-mail address removed) 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
 

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,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top