Pointer to OVERLOADED member function?

S

Somebody

Given this class:

class A
{
public:
int Test()
{
return 0;
}

int Test(int a)
{
return 1;
}
};

how can I get the following code to work?

LPVOID lpv = (LPVOID&)A::Test;

If I comment out the 2nd overloaded Test(int) function, this compiles just
fine and does whats expected. If I leave Test(int) in the code, the compiler
actually ** CRASHES ** with an internal compiler error (Visual Studio 2008).

Obviously the issue here is how do I differentiate between the two functions
when I am trying to get the pointer to the function?

Please note, I CAN NOT rename either of the functions and I CAN NOT add
another function which wraps the overloaded function in a derived class as I
** MUST ** have the exact address of the A::Test(int) function for hooking
purposes.
 
T

tragomaskhalos

Given this class:

class A
{
public:
    int Test()
    {
        return 0;
    }

    int Test(int a)
    {
        return 1;
    }

};

how can I get the following code to work?

LPVOID lpv = (LPVOID&)A::Test;

If I comment out the 2nd overloaded Test(int) function, this compiles just
fine and does whats expected. If I leave Test(int) in the code, the compiler
actually ** CRASHES ** with an internal compiler error (Visual Studio 2008).

Obviously the issue here is how do I differentiate between the two functions
when I am trying to get the pointer to the function?

Please note, I CAN NOT rename either of the functions and I CAN NOT add
another function which wraps the overloaded function in a derived class as I
** MUST ** have the exact address of the A::Test(int) function for hooking
purposes.

For starters,
LPVOID lpv = (LPVOID&)A::Test;
doesn't make sense - you're casting to a reference to a void*.

You can start with this:
int (A::*mfp_int)(int) = &A::Test;
int (A::*mfp_void)() = &A::Test;

to get your method disambiguation working, but this isn't
going to help you, because you then say:
"I ** MUST ** have the exact address of the A::Test(int)
function for hooking purposes.", which leads me to
believe that you are about to make the common mistake of
confusing a pointer-to-function with pointer-to-member-
function. These two are completely different and not
interchangeable.
 
J

James Kanze

Given this class:
class A
{
public:
int Test()
{
return 0;
}
int Test(int a)
{
return 1;
}
};
how can I get the following code to work?
LPVOID lpv = (LPVOID&)A::Test;

What is LPVOID? It can't be void*, since you can't convert a
pointer to member function, or even a pointer to a non-member
function, to a void*. And I can't think of what else it could
be. (FWIW: some compilers, e.g. g++, seem to be a bit lax and
allow the conversion of a pointer to function to void*. But
I've never used a compiler where a pointer to a member function
would fit into a void*.)
If I comment out the 2nd overloaded Test(int) function, this
compiles just fine and does whats expected.

Which is?
If I leave Test(int) in the code, the compiler actually **
CRASHES ** with an internal compiler error (Visual Studio
2008).

Well, any time the compiler crashes, it is an error in the
compiler, so you know where to ask.
Obviously the issue here is how do I differentiate between the
two functions when I am trying to get the pointer to the
function?

Function overload resolution for taking the address of a pointer
can work in two ways:

-- if the address is immediately assigned to a variable, then
the type of the variable will be used for overload
resolution; otherwise,

-- you have to specify the type of the address explicitly,
using one of the cast notations, e.g.:
static_cast< int (A::*)( int ) >( &A::Test )
or
static_cast< int (A::*)() >( &A::Test )
 
S

Somebody

Please see my other response to the other guy as you both had the same
questions about my question :).

Given this class:
class A
{
public:
int Test()
{
return 0;
}
int Test(int a)
{
return 1;
}
};
how can I get the following code to work?
LPVOID lpv = (LPVOID&)A::Test;

What is LPVOID? It can't be void*, since you can't convert a
pointer to member function, or even a pointer to a non-member
function, to a void*. And I can't think of what else it could
be. (FWIW: some compilers, e.g. g++, seem to be a bit lax and
allow the conversion of a pointer to function to void*. But
I've never used a compiler where a pointer to a member function
would fit into a void*.)
If I comment out the 2nd overloaded Test(int) function, this
compiles just fine and does whats expected.

Which is?
If I leave Test(int) in the code, the compiler actually **
CRASHES ** with an internal compiler error (Visual Studio
2008).

Well, any time the compiler crashes, it is an error in the
compiler, so you know where to ask.
Obviously the issue here is how do I differentiate between the
two functions when I am trying to get the pointer to the
function?

Function overload resolution for taking the address of a pointer
can work in two ways:

-- if the address is immediately assigned to a variable, then
the type of the variable will be used for overload
resolution; otherwise,

-- you have to specify the type of the address explicitly,
using one of the cast notations, e.g.:
static_cast< int (A::*)( int ) >( &A::Test )
or
static_cast< int (A::*)() >( &A::Test )
 
S

Somebody

Allow me to explain further... I left out this part of the explanation as it
is OS specific...

* let there be a FOO.DLL (or FOO.LIB if compiling in static lib mode)

* let FOO.DLL / FOO.LIB contain a class called CFoo

* let CFoo contain a function called Foo() that has several overloads
including a static version

* The DLL / LIB is MFC, and one of the Foo() functions has a bug which I am
developing a workaround for. Foo() is not virtual and while it can be
patched in a derived class, I need to trap all uses of Foo() -- some of
which are not in my control. I can't tell Microsoft to use my derived class
:).

* So, my class library already has some API hooking functionality. I want to
hook the CFoo::Foo() that has the issue and fix it.

* To hook it, I need the exact address of CFoo::Foo() (ie a void* pointer to
the code). In other words, I can do this in the DLL version by calling
GetProcAddress(), but that'll only work for the DLL version, and CFoo::Foo()
is only exported by ordinal (which can obviously change for every binary
version).

So, end result is that I need to get a pointer to the code, so I can hook it
with my API hooking functions.

If there is no overload, I can get the address of the code, once an overload
is introduced, the compiler can not resolve the ambiguity.
 
T

tragomaskhalos

Allow me to explain further... I left out this part of the explanation as it
is OS specific...

* let there be a FOO.DLL (or FOO.LIB if compiling in static lib mode)

* let FOO.DLL / FOO.LIB contain a class called CFoo

* let CFoo contain a function called Foo() that has several overloads
including a static version

* The DLL / LIB is MFC, and one of the Foo() functions has a bug which I am
developing a workaround for. Foo() is not virtual and while it can be
patched in a derived class, I need to trap all uses of Foo() -- some of
which are not in my control. I can't tell Microsoft to use my derived class
:).

* So, my class library already has some API hooking functionality. I want to
hook the CFoo::Foo() that has the issue and fix it.

* To hook it, I need the exact address of CFoo::Foo() (ie a void* pointer to
the code). In other words, I can do this in the DLL version by calling
GetProcAddress(), but that'll only work for the DLL version, and CFoo::Foo()
is only exported by ordinal (which can obviously change for every binary
version).

So, end result is that I need to get a pointer to the code, so I can hook it
with my API hooking functions.

If there is no overload, I can get the address of the code, once an overload
is introduced, the compiler can not resolve the ambiguity.

It's still not clear whether you're interested in the static
Foo()s, or the member Foo()s, or both.

But going back to your original example with members, have
you tried:

void* extremely_dodgy_1 = reinterpret_cast<void*>(
static_cast<int (A::*)(int)>(&A::Test));

void* extremely_dodgy_2 = reinterpret_cast<void*>(
static_cast<int (A::*)()>(&A::Test));

Like James I can't see how a member function pointer
can usably be scrunched into a void* in this way, and
Comeau Online quite reasonably refuses to even
compile this code. However, since you're doing something
extremely grungy and OS-specific, and claim that it
"works" with your compiler in the non-overload case,
(again, I'm surprised it even compiles, but I'll take
your word for it) give it a go, bearing in mind that
my variables are very aptly named.
 
J

James Kanze

It's still not clear whether you're interested in the static
Foo()s, or the member Foo()s, or both.
But going back to your original example with members, have
you tried:
void* extremely_dodgy_1 = reinterpret_cast<void*>(
static_cast<int (A::*)(int)>(&A::Test));
void* extremely_dodgy_2 = reinterpret_cast<void*>(
static_cast<int (A::*)()>(&A::Test));
Like James I can't see how a member function pointer
can usably be scrunched into a void* in this way, and
Comeau Online quite reasonably refuses to even
compile this code. However, since you're doing something
extremely grungy and OS-specific, and claim that it
"works" with your compiler in the non-overload case,
(again, I'm surprised it even compiles, but I'll take
your word for it) give it a go, bearing in mind that
my variables are very aptly named.

I'm not sure, but I have the impression that he really is trying
to intercept the function at its lowest level. He doesn't want
the address of the function, in the C++ sense, but the physical
address of the code which actually implements the function. And
since the machine he's running on doesn't use a Harvard
architecture, nor some sort of different segmentation model for
code and data, he probably can represent that in a void*
(although in many ways, a uint32_t would be more appropriate).
On the other hand, if that is his problem, there's nothing in
C++ per se to help him. He'll have to find out somehow how
pointer to member functions are implemented by his compiler, and
work from there to find the physical address. There will be
one somewhere, of course, because in the end, the function does
get called. But if the compiler uses trampolines of some sort,
he may have to do some dynamic disassembly. On the other hand,
if the function isn't virtual, there's a good chance that the
physical address is located somewhere in the pointer to member.
Where is, of course, another question.
 
S

Somebody

Yes James,

I was trying to get a void* to the CODE bytes of CFoo::Foo()...

Anyways, I got it working :). Just a syntactical error on my side :).



I'm not sure, but I have the impression that he really is trying
to intercept the function at its lowest level. He doesn't want
the address of the function, in the C++ sense, but the physical
address of the code which actually implements the function. And
since the machine he's running on doesn't use a Harvard
architecture, nor some sort of different segmentation model for
code and data, he probably can represent that in a void*
(although in many ways, a uint32_t would be more appropriate).
On the other hand, if that is his problem, there's nothing in
C++ per se to help him. He'll have to find out somehow how
pointer to member functions are implemented by his compiler, and
work from there to find the physical address. There will be
one somewhere, of course, because in the end, the function does
get called. But if the compiler uses trampolines of some sort,
he may have to do some dynamic disassembly. On the other hand,
if the function isn't virtual, there's a good chance that the
physical address is located somewhere in the pointer to member.
Where is, of course, another question.
 
J

James Kanze

I was trying to get a void* to the CODE bytes of CFoo::Foo()...

You mean, to look at them as data. Formally, C++ doesn't allow
this, and on some hardwares I've used, it isn't possible. (But
it doesn't sound like you're looking for a universally portable
solution anyway.)
Anyways, I got it working :). Just a syntactical error on my side :).

If that's the case, you're using an extension of the compiler.
The only way to legally convert a pointer to member function to
a void* is by type punning (which of course is very
implementation dependent); something like:

void (A::*pmf)() ;
void * p = *reinterpret_cast< void** >( &pmf ) ;

The results are very implementation defined.

If pmf were a pointer to a function, and not a pointer to a
member function, Posix requires the above to work. Although I
don't know of any official requirement, it will also work under
Windows. When, as is the case here, pmf is a pointer to member,
it's a lot chancier---it depends on the implementation of
pointer to members. (You might have to add something to the
cast void**, for example.)

Also, if you are using VC++, be very, very careful. VC++ uses
several different implementations of pointer to member
functions, according to the amount of information available to
it; the format used might depend on the header files included,
for example. (This is not standard conformant, in that programs
that are legal according to the standard compile without error,
but fail to execute correctly.) I would strongly recommend
using the option /vmg, which tells the compiler to handle
pointers to member functions in the same way everywhere.
 

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

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top