 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Andy Guest
|
Posted: Fri Apr 29, 2005 8:42 am Post subject: What's wrong with this segment of code? |
|
|
Hi,
Sorry for the naive question. What I did here is to check the value of
pointers to member functions, and try to call these member function via
member functio pointers.
But running with gcc, it gives out segment fault. What's wrong with my
code?
Here is the code:
#include <iostream>
using namespace std;
class A{
public:
int method1(int a, int b){ cout<<"Hello,world"; return 0; }
int method2(int a, int b) { return a + b; }
int method3(int x, int y) { return x * x;}
};
void conv_ptr(void * ptr, char* buf)
{
char * str = (char*)ptr;
int i;
for(i = 0; i < 4 ; i++)
sprintf(buf+i*2, "%.2x", str[i]);
buf[8] = 0;
}
int main()
{
A a;
int (A::*ptr) (int, int) ;
char buf[9];
ptr = &A::method1;
conv_ptr(&ptr, buf);
cout<<"ptr ="<
cout<<(a.*ptr)(5,5)<
ptr = &A::method2;
conv_ptr(&ptr, buf);
cout<<"ptr ="<
cout<<(a.*ptr)(5,5)<
ptr = &A::method3;
conv_ptr(&ptr, buf);
cout<<"ptr ="<
cout<<(a.*ptr)(5,5)<
}
Thanks !
Andy
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Sat Apr 30, 2005 11:19 am Post subject: Re: What's wrong with this segment of code? |
|
|
Andy wrote:
| Quote: | Sorry for the naive question. What I did here is to check the
value of pointers to member functions, and try to call these
member function via member functio pointers. But running with
gcc, it gives out segment fault. What's wrong with my code?
|
Buffer overrun. I'm tempted to say: "you asked for it, you got
it"; it's extremely difficult to write a correct program using
sprintf (and imposible to write one which is both correct and
maintainable).
| Quote: | Here is the code:
#include <iostream
using namespace std;
class A{
public:
int method1(int a, int b){ cout<<"Hello,world"; return 0; }
int method2(int a, int b) { return a + b; }
int method3(int x, int y) { return x * x;}
};
void conv_ptr(void * ptr, char* buf)
{
char * str = (char*)ptr;
int i;
for(i = 0; i < 4 ; i++)
sprintf(buf+i*2, "%.2x", str[i]);
|
And how big is buf?
Note that on most machines, char will be signed. str[i]
converts implicitly to int when passed as a variadic arg -- if
char is signed, this will sometimes be a negative number. The
format specifier %.2x treats this (the bit pattern, not the
value -- the normal rules of conversion don't apply) as an
unsigned int, and the bit pattern of a negative int will usually
result in a pretty large unsigned number. From the values of
your magic constants, I'd guess that you're on a 32 bit machine,
which means that you'll generate 8 digits, instead of 2. If the
target buffer isn't big enough...
sprintf does append a ' ' to the end. (Of course, in your
case, the "end" might not be where you think it is:-).)
What's wrong with something like:
std::string
dump( void* value, size_t size )
{
std::ostringstream s ;
s.setf( std::ios::hex, std::ios::basefield ) ;
s.fill( '0' ) ;
unsigned char* p = static_cast< unsigned char* >( value )
;
// unsigned char, to avoid the problem
// mentionned above.
for ( size_t i = 0 ; i < size ; ++ i ) {
s << std::setw( 2 ) << (int)[[ i ] ;
// conversion to int so that the stream formats
// it as a numeric value, rather than treating
// it as a character.
}
return s.str() ;
}
This way, you're sure that there are no buffer overflow
problems.
| Quote: | int main()
{
A a;
int (A::*ptr) (int, int) ;
char buf[9];
|
Which won't be big enough if the last byte passed is greater
than 0x7F.
| Quote: | ptr = &A::method1;
conv_ptr(&ptr, buf);
|
You do realize that the size of a pointer to member isn't
necessarily four, even on a 32 bit machine. (The size of a
pointer to member function will typically be at least twice the
size of a normal pointer, often even more. Unless the
implemention uses trampolines, which is, I think, the case of
g++.)
Using the above function:
std::cout << "ptr = " << dump( &ptr, sizeof( ptr ) ) << std::endl ;
| Quote: | cout<<(a.*ptr)(5,5)<
ptr = &A::method2;
conv_ptr(&ptr, buf);
cout<<"ptr ="<
cout<<(a.*ptr)(5,5)<
ptr = &A::method3;
conv_ptr(&ptr, buf);
cout<<"ptr ="<
cout<<(a.*ptr)(5,5)<
}
|
If you really want to start understanding pointers to member
functions, you'll have to dump some which contain pointers to
virtual functions. Maybe once as a int(B::*)(int,int), and once
as a int(D::*)(int,int). You might want to see what effect (if
any) multiple base classes and virtual bases have. You might
want to assign a int(B::*)(int,int) to a int(D::*)(int,int), and
dump both.
You might also want to try it with different compilers. Not all
compilers use the same implementation.
--
James Kanze GABI Software
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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Nickolay Merkin Guest
|
Posted: Sat Apr 30, 2005 11:29 am Post subject: Re: What's wrong with this segment of code? |
|
|
Nice feature...
I played with VC6, and found that
template<class T>
void conv_ptr(T* ptr, char* buf)
{
char * str = (char*)ptr;
int i;
for(i = 0; i < 4 ; i++)
sprintf(buf+i*2, "%.2x", str[i]);
buf[8] = 0;
}
prints 30124000, 60124000, ff124000
but if I turn back to
void conv_ptr(void* ptr, char* buf)
it prints
ff124000, ff124000, ff124000
Moreover, when I added fourth method, I got
ff124000, ff124000, ff124000, 00134000
in both cases.
It seems that getting address of a pointer-to-member-function variable
is undefined.
But why?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Nickolay Merkin Guest
|
Posted: Sat Apr 30, 2005 11:34 am Post subject: Re: What's wrong with this segment of code? |
|
|
I posted this question on RSDN (www.rsdn.ru) and they noticed me
that
char * str = (char*)ptr;
should be replaced with
unsigned char * str = (unsigned char*)ptr;
Aha! I caught what happens.
Some of these bytes have high bit=1,
and treated as negative char values.
Passing a char to ... (in sprintf) promotes it to int,
so these bytes are treated as negative ints.
sprintf %.2x prints AT LEAST 2 hex digits,
but a negative int is a very big unsigned, so sprintf puts 8
characters.
Beginning with i=1 and more, we overrun the char buf[8] and shoot the
stack.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Martin Bonner Guest
|
Posted: Sat Apr 30, 2005 4:13 pm Post subject: Re: What's wrong with this segment of code? |
|
|
k... (AT) gabi-soft (DOT) fr wrote:
| Quote: | conv_ptr(&ptr, buf);
You do realize that the size of a pointer to member isn't
necessarily four, even on a 32 bit machine.
|
But he isn't displaying the pointer-to-member. He is displaying the
address of the object called 'ptr' (which happens to be of type pointer
to member).
This may well the OPs next problem of course. He needs to start
dumping the content of ptr rather than its address.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|