Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Change one function pointer in Vtable

179 views
Skip to first unread message

Frederick Gotham

unread,
Jun 8, 2020, 9:13:59 AM6/8/20
to

There is a class which has a Vtable containing the addresses of all the class's (and base classes's) virtual functions.

At any given time, there might be about a dozen instances (i.e. a dozen objects) of this class in existence, and objects are continuously being created and destroyed.

When a physical pin is set high (i.e. set to 3.3 volts), it will cause an interrupt to fire and so the main program will be frozen. In the interrupt routine, I want to alter one of the addresses in the class's vtable before handing control back to the main program. So from that point forward, any calls to a virtual method will call the new function whose address I have set. If the interrupt fires again in future, I will again change the vtable.

Anyone ever done this before?

Of course I will have to make sure that there isn't any optimisation where the compiler can predict which function will be called on the current object.

The beginning of psuedo-code would be something like:

extern int Some_Other_Function(int); // Defined in another file

void Interrupt_Routine(void)
{
MyClass obj;

VTable &vtable = *reinterpret_cast<Vtable*>(&obj); // std::launder?

vtable.SomeFunction = SomeOtherFunction;
}

int main(void)
{
Register_Interrupt(PIN4, Interrupt_Routine);

for ( ; /* ever */ ; )
{
MyClass obj;

obj.SomeFunction(); // Make sure compiler doesn't hardcode func address
}
}



Alf P. Steinbach

unread,
Jun 8, 2020, 9:35:51 AM6/8/20
to
On 08.06.2020 15:13, Frederick Gotham wrote:
>
> There is a class which has a Vtable containing the addresses of all the class's (and base classes's) virtual functions.
>
> At any given time, there might be about a dozen instances (i.e. a dozen objects) of this class in existence, and objects are continuously being created and destroyed.
>
> When a physical pin is set high (i.e. set to 3.3 volts), it will cause an interrupt to fire and so the main program will be frozen. In the interrupt routine, I want to alter one of the addresses in the class's vtable before handing control back to the main program.

No. NO. NO!


> So from that point forward, any calls to a virtual method will call the new function whose address I have set. If
> the interrupt fires again in future, I will again change the vtable.
>
> Anyone ever done this before?

Some colleagues of mine, fresh out of school, decided to make a lot of
trouble for themselves in 1999 or thereabouts. They did the alter-vtable
thing in Visual Basic. And then came to me to ask what on Earth could be
the reason for the mysterious crashes.

They failed to add the lunacy of doing this in an interrupt handler.

But they did add another sort of same level of dumbness thing, with each
class in its own Windows DLL. They wondered why the app was so slow to load.


> Of course I will have to make sure that there isn't any optimisation
> where the compiler can predict which function will be called on the
> current object.

Just don't.


> The beginning of psuedo-code would be something like:
>
> extern int Some_Other_Function(int); // Defined in another file
>
> void Interrupt_Routine(void)
> {
> MyClass obj;
>
> VTable &vtable = *reinterpret_cast<Vtable*>(&obj); // std::launder?
>
> vtable.SomeFunction = SomeOtherFunction;
> }
>
> int main(void)
> {
> Register_Interrupt(PIN4, Interrupt_Routine);
>
> for ( ; /* ever */ ; )
> {
> MyClass obj;
>
> obj.SomeFunction(); // Make sure compiler doesn't hardcode func address
> }
> }

Don't.


- Alf

David Brown

unread,
Jun 8, 2020, 9:44:27 AM6/8/20
to
On 08/06/2020 15:13, Frederick Gotham wrote:
>
> There is a class which has a Vtable containing the addresses of all
> the class's (and base classes's) virtual functions.
>
> At any given time, there might be about a dozen instances (i.e. a
> dozen objects) of this class in existence, and objects are
> continuously being created and destroyed.
>
> When a physical pin is set high (i.e. set to 3.3 volts), it will
> cause an interrupt to fire and so the main program will be frozen. In
> the interrupt routine, I want to alter one of the addresses in the
> class's vtable before handing control back to the main program. So
> from that point forward, any calls to a virtual method will call the
> new function whose address I have set. If the interrupt fires again
> in future, I will again change the vtable.
>
> Anyone ever done this before?
>
> Of course I will have to make sure that there isn't any optimisation
> where the compiler can predict which function will be called on the
> current object.
>

To expand on Alf's comment - don't do it.

Whenever you think "I'll have to disable some optimisations for this to
work", your idea is *bad*. Lying to the compiler is not a good idea.

Make a single static (probably volatile) variable in the class that
tracks which function you'll want to call. Your virtual function - if
indeed it needs to be virtual - will check that variable to decide what
to do. (Prefer a check on the variable followed by a conditional or
switch to using a function pointer - it's easier to get right, and will
usually be more efficient.)

What made you think this could be a good idea in the first place?

Öö Tiib

unread,
Jun 8, 2020, 10:39:08 AM6/8/20
to
On Monday, 8 June 2020 16:13:59 UTC+3, Frederick Gotham wrote:
> There is a class which has a Vtable containing the addresses of all the class's (and base classes's) virtual functions.
>
> At any given time, there might be about a dozen instances (i.e. a dozen objects) of this class in existence, and objects are continuously being created and destroyed.
>
> When a physical pin is set high (i.e. set to 3.3 volts), it will cause an interrupt to fire and so the main program will be frozen. In the interrupt routine, I want to alter one of the addresses in the class's vtable before handing control back to the main program. So from that point forward, any calls to a virtual method will call the new function whose address I have set. If the interrupt fires again in future, I will again change the vtable.
>
> Anyone ever done this before?


Why to screw with undocumented features of implementation if it
can be written in fully well-defined manner? Black magic is
generally frowned upon and often considered to be sabotage of
code base.

> Of course I will have to make sure that there isn't any optimisation where the compiler can predict which function will be called on the current object.

:D Turning off optimizations means that the trash will be
inefficient on top of being buggy.

Paavo Helde

unread,
Jun 8, 2020, 11:44:32 AM6/8/20
to
08.06.2020 16:13 Frederick Gotham kirjutas:
>
> There is a class which has a Vtable containing the addresses of all the class's (and base classes's) virtual functions.
>
> At any given time, there might be about a dozen instances (i.e. a dozen objects) of this class in existence, and objects are continuously being created and destroyed.
>
> When a physical pin is set high (i.e. set to 3.3 volts), it will cause an interrupt to fire and so the main program will be frozen. In the interrupt routine, I want to alter one of the addresses in the class's vtable

Do not do that, ever! This is akin to asking whether it is a good idea
to break into a transformer booth and reconnect live wires with bare hands.

If you want to change some state in the interrupt, store the state in a
(volatile) enum variable and change that, as suggested by others. You
can dispatch to different functions easily based on that state.

Manfred

unread,
Jun 8, 2020, 12:29:52 PM6/8/20
to
On 6/8/2020 3:13 PM, Frederick Gotham wrote:
>
> There is a class which has a Vtable containing the addresses of all the class's (and base classes's) virtual functions.
>
> At any given time, there might be about a dozen instances (i.e. a dozen objects) of this class in existence, and objects are continuously being created and destroyed.
>
> When a physical pin is set high (i.e. set to 3.3 volts), it will cause an interrupt to fire and so the main program will be frozen. In the interrupt routine, I want to alter one of the addresses in the class's vtable before handing control back to the main program. So from that point forward, any calls to a virtual method will call the new function whose address I have set. If the interrupt fires again in future, I will again change the vtable.

Despite the lack of originality, don't do that(!)

The main reason is that, although there possibly is a vtable in your
objects, touching anything in that area drowns in undefined behavior -
the language mandates specific rules on how to handle a pointer to an
object for this very reason.

If you want, by design, manipulate a function pointer, or an array
thereof, then do just that - set up your own array of function pointers,
and manipulate it according to the language rules.
However, given the possibilities of modern C++ I doubt that it is really
necessary to do even that.
The specifics of interrupt handlers apply on top of the above.

Scott Newman

unread,
Jun 8, 2020, 12:43:38 PM6/8/20
to
Of course you can customize the vtable this way.

Scott Newman

unread,
Jun 8, 2020, 12:54:18 PM6/8/20
to
> Of course you can customize the vtable this way.

It would be the best to scan the vtable linearly for a known
method-address and replace that address with the method you
like. You can simply take a function whose first parameter
will take the this pointer.
There might be implementations where this won't work, but
currently there isn't any.

Mr Flibble

unread,
Jun 8, 2020, 1:04:53 PM6/8/20
to
What century is this? Use std::atomic not volatile.

>
> What made you think this could be a good idea in the first place?

/Flibble

--
"Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin

“You won’t burn in hell. But be nice anyway.” – Ricky Gervais

“I see Atheists are fighting and killing each other again, over who doesn’t believe in any God the most. Oh, no..wait.. that never happens.” – Ricky Gervais

"Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say."

Mr Flibble

unread,
Jun 8, 2020, 1:06:55 PM6/8/20
to
Either:

a) you are trolling;

or:

b) you are a fucking idiot.

DO NOT DO THIS -- IT IS UNDEFINED BEHAVIOUR *AT BEST*.

Scott Newman

unread,
Jun 8, 2020, 1:20:51 PM6/8/20
to
> DO NOT DO THIS -- IT IS UNDEFINED BEHAVIOUR *AT BEST*.

All C++-compilers handle vtables in a similar way.
If you stick to one implementation that's quite manageable.

Mr Flibble

unread,
Jun 8, 2020, 1:34:46 PM6/8/20
to
Except there is no good reason to even do this; none at all.

Manfred

unread,
Jun 8, 2020, 1:36:20 PM6/8/20
to
On 6/8/2020 7:04 PM, Mr Flibble wrote:
> On 08/06/2020 14:44, David Brown wrote:
>>
>> Make a single static (probably volatile) variable in the class that
>> tracks which function you'll want to call.  Your virtual function - if
>> indeed it needs to be virtual - will check that variable to decide
>> what to do.  (Prefer a check on the variable followed by a conditional
>> or switch to using a function pointer - it's easier to get right, and
>> will usually be more efficient.)
>
> What century is this? Use std::atomic not volatile.
>

Actually, an interrupt handler is exactly the purpose that volatile is
designed for: it tells the compiler that a variable may change its value
outside the flow of operation as seen by the compiler.

The fact that the keyword has been used in the context of multithreading
as a surrogate for atomic access is the tangent side use.

However, I am not totally with David Brown on preferring a conditional
to a function pointer - of course it depends on the specific case, and
it may be a matter of taste.

Scott Newman

unread,
Jun 8, 2020, 1:39:37 PM6/8/20
to
>> All C++-compilers handle vtables in a similar way.
>> If you stick to one implementation that's quite manageable.

> Except there is no good reason to even do this; none at all.

In most cases you only use one compiler.
So in most cases there's not a problem with this.

Mr Flibble

unread,
Jun 8, 2020, 1:40:32 PM6/8/20
to
So my conclusion is that you are a troll.

Bonita Montero

unread,
Jun 8, 2020, 1:40:53 PM6/8/20
to
Use non-virtual functions which dispatch according to your
own virtual function tables.

Scott Newman

unread,
Jun 8, 2020, 1:41:37 PM6/8/20
to
>> In most cases you only use one compiler.
>> So in most cases there's not a problem with this.

> So my conclusion is that you are a troll.

No, I am a practitioner while you are a theorist.

Mr Flibble

unread,
Jun 8, 2020, 1:49:22 PM6/8/20
to
On 08/06/2020 18:36, Manfred wrote:
> On 6/8/2020 7:04 PM, Mr Flibble wrote:
>> On 08/06/2020 14:44, David Brown wrote:
>>>
>>> Make a single static (probably volatile) variable in the class that tracks which function you'll want to call.  Your virtual function - if indeed it needs to be virtual - will check that variable to decide what to do.  (Prefer a check on the variable followed by a conditional or switch to using a function pointer - it's easier to get right, and will usually be more efficient.)
>>
>> What century is this? Use std::atomic not volatile.
>>
>
> Actually, an interrupt handler is exactly the purpose that volatile is designed for: it tells the compiler that a variable may change its value outside the flow of operation as seen by the compiler.

Nonsense. Disable interrupts much? std::atomic is the superior solution for ISRs these days. Stop living in the past.

>
> The fact that the keyword has been used in the context of multithreading as a surrogate for atomic access is the tangent side use.

The fact that people write shite code is orthogonal to this discussion.

>
> However, I am not totally with David Brown on preferring a conditional to a function pointer - of course it depends on the specific case, and it may be a matter of taste.

Indeed.

David Brown

unread,
Jun 8, 2020, 1:52:57 PM6/8/20
to
On 08/06/2020 19:36, Manfred wrote:
> On 6/8/2020 7:04 PM, Mr Flibble wrote:
>> On 08/06/2020 14:44, David Brown wrote:
>>>
>>> Make a single static (probably volatile) variable in the class that
>>> tracks which function you'll want to call.  Your virtual function -
>>> if indeed it needs to be virtual - will check that variable to decide
>>> what to do.  (Prefer a check on the variable followed by a
>>> conditional or switch to using a function pointer - it's easier to
>>> get right, and will usually be more efficient.)
>>
>> What century is this? Use std::atomic not volatile.
>>
>
> Actually, an interrupt handler is exactly the purpose that volatile is
> designed for: it tells the compiler that a variable may change its value
> outside the flow of operation as seen by the compiler.
>

Exactly. "Atomic" would be slightly inappropriate (though it would
probably work fine here).

> The fact that the keyword has been used in the context of multithreading
> as a surrogate for atomic access is the tangent side use.
>
> However, I am not totally with David Brown on preferring a conditional
> to a function pointer - of course it depends on the specific case, and
> it may be a matter of taste.

Of course it can vary by detail of the case, and personal preference.
As a general rule, I usually choose a conditional or switch rather than
a function pointer because it gives the compiler far more information
for optimisation purposes, and it makes it much easier to follow the
flow of the code when reading it, generating call graphs, etc. If your
code has no function pointers (or none of a particular type), then it's
easy to find every part of your code that calls the function "foo" - you
just search for all calls to "foo". If "foo" might have been assigned
to a function pointer, such searches are a lot more complicated.

It does come at the cost that it can lead to more inter-dependencies
between modules that could be avoided by function pointers and
call-backs, so there are pros and cons.

But since the OP is talking about interrupts, I'm assuming it will be a
low-level program and probably fairly small, so I'd start with a
variable and conditionals until convinced function pointers are better.

Keith Thompson

unread,
Jun 8, 2020, 2:03:15 PM6/8/20
to
The OP wants to alter which function is called with a given name.

Isn't that exactly what function pointers are for?

Even if the language guaranteed the behavior of vtables (or mentioned
them at all!), what would be the advantage of modifying a vtable
rather than using a function pointer?

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

Scott Newman

unread,
Jun 8, 2020, 2:07:57 PM6/8/20
to
> Even if the language guaranteed the behavior of vtables (or mentioned
> them at all!), what would be the advantage of modifying a vtable
> rather than using a function pointer?

You won't have to deal with implementing your own vtable structure.

James Kuyper

unread,
Jun 8, 2020, 2:26:20 PM6/8/20
to
On 6/8/20 12:43 PM, Scott Newman wrote:
> Of course you can customize the vtable this way.

The kind of type-punning needed to do anything like this has undefined
behavior. This means, for instance, that an implementation is free to
cache vtable pointer somewhere and continue using the cached version,
even after you've changed the one in memory. However, the opportunities
for something to go wrong are much worse than that.

James Kuyper

unread,
Jun 8, 2020, 2:27:10 PM6/8/20
to
They're not required to do so, and I'd be surprised (or more accurately,
astounded) if they all did it in exactly the same way.

James Kuyper

unread,
Jun 8, 2020, 2:28:47 PM6/8/20
to
At the cost of having to determine what the implementation's vtable
structure is, and at the cost of rendering the behavior of your program
undefined. An ordinary function pointer is a far better way of
implementing this.

Scott Newman

unread,
Jun 8, 2020, 2:32:18 PM6/8/20
to
> At the cost of having to determine what the implementation's vtable
> structure is, and at the cost of rendering the behavior of your program
> undefined. An ordinary function pointer is a far better way of
> implementing this.

No, you will get an integration of your own functions in the vtable
and not a single function-pointer for each function in the object.
That's a lot less space.
And usually you stay with one implementation where this is reliable.

Scott Newman

unread,
Jun 8, 2020, 2:33:03 PM6/8/20
to
> They're not required to do so, and I'd be surprised (or more
> accurately, astounded) if they all did it in exactly the same way.

The way is still the same since cfront for all C++-compilers.

Scott Newman

unread,
Jun 8, 2020, 2:34:22 PM6/8/20
to
> The kind of type-punning needed to do anything like this has undefined
> behavior.

Doesn't matter if you stay with one impementation. The OP is talking
about interrupt-handlers, so it's very unlikely that he needs code
that is portable across all compilers.

Paavo Helde

unread,
Jun 8, 2020, 2:47:23 PM6/8/20
to
08.06.2020 21:03 Keith Thompson kirjutas:
> Scott Newman <sco...@gmail.com> writes:
>>> DO NOT DO THIS -- IT IS UNDEFINED BEHAVIOUR *AT BEST*.
>>
>> All C++-compilers handle vtables in a similar way.
>> If you stick to one implementation that's quite manageable.
>
> The OP wants to alter which function is called with a given name.
>
> Isn't that exactly what function pointers are for?

In C, yes. C++ provides better means to achieve the same, namely virtual
functions, functors and lambdas.

In this scenario virtual functions are not applicable, so one could use
a functor (a std::function variable), which can be easily assigned by
using a lambda.

However, if the repertoire of functions involved is small and fixed (as
I suspect is the case in this scenario), a simple state variable might
appear more readable and maintainable. But this depends on the usage
details.

> Even if the language guaranteed the behavior of vtables (or mentioned
> them at all!), what would be the advantage of modifying a vtable
> rather than using a function pointer?

I have come to a conclusion there is almost no usage case for plain
function pointers in C++. Nearly always one also wants to pass extra
data which can be done very conveniently with a lambda.

Paavo Helde

unread,
Jun 8, 2020, 2:53:17 PM6/8/20
to
Until the next compiler version or an innocent compilation flag will
optimize away or otherwise break your undefined behavior.

C++ does not have a shortage of ways how to shoot yourself in foot
inadvertently. There is no reason to do the same intentionally.



Mr Flibble

unread,
Jun 8, 2020, 2:55:34 PM6/8/20
to
You are manifesting a combination of the two greatest evils: obtuseness and wrongness. How many times have you been fired from your job out of interest?

Scott Newman

unread,
Jun 8, 2020, 2:58:57 PM6/8/20
to
>> And usually you stay with one implementation where this is reliable.

> Until the next compiler version or an innocent compilation flag will
> optimize away or otherwise break your undefined behavior.

That'S very unlikely with such a basic feature.

Scott Newman

unread,
Jun 8, 2020, 3:01:31 PM6/8/20
to
>> Doesn't matter if you stay with one impementation. The OP is talking
>> about interrupt-handlers, so it's very unlikely that he needs code
>> that is portable across all compilers.

> You are manifesting a combination of the two greatest evils: obtuseness
> and wrongness. How many times have you been fired from your job out of
> interest?

I have been working as a developer for a long time. And my bosses
were always happy with my job. There have never been any problems
with my programming style.
But you are a theoretician who has nothing to do with practice.

James Kuyper

unread,
Jun 8, 2020, 3:01:32 PM6/8/20
to
How many different implementation of C++ have you actually verified that
assumption for? Please list them.

Scott Newman

unread,
Jun 8, 2020, 3:04:45 PM6/8/20
to
>> The way is still the same since cfront for all C++-compilers.

> How many different implementation of C++ have you actually verified that
> assumption for? Please list them.

It's just the most obvious way to do it like Cfront.
And there is no reason to do it differently.
And with all compilers for Windows it is even more important
to do it that way because COM is based on this vtable layout;
other component-object-models handle it similary.

James Kuyper

unread,
Jun 8, 2020, 3:07:56 PM6/8/20
to
If the one implementation you're doing it with is one of the ones that
takes advantage of the fact that it has undefined behavior to do
something you didn't think it could do, no, you can't do that.

Please note that it's not sufficient to simply experiment and verify
that it works. If the implementation doesn't provide any guarantees
about what the behavior will be if you do something like this, it's
entirely possible that it will appear to work in every situation you
think of testing, but will fail in a situation that you didn't think to
test, possibly for reasons that you completely failed to imagine could
be relevant.

Please cite for me at least one implementation of C++ that provides
guarantees about what would happen if your code modifies the vtable, and
please tell us precisely what it guarantees about that behavior.

Scott Newman

unread,
Jun 8, 2020, 3:09:51 PM6/8/20
to
> If the one implementation you're doing it with is one of the ones that
> takes advantage of the fact that it has undefined behavior to do
> something you didn't think it could do, no, you can't do that.

The whole thing is predictable since no compiler behaves differently
than cfront.

Paavo Helde

unread,
Jun 8, 2020, 3:11:27 PM6/8/20
to
UB is a bug, not a feature.

Scott Newman

unread,
Jun 8, 2020, 3:12:20 PM6/8/20
to
>> That'S very unlikely with such a basic feature.

> UB is a bug, not a feature.

UB is what the standard says, not the implementation.

James Kuyper

unread,
Jun 8, 2020, 3:12:24 PM6/8/20
to
On 6/8/20 3:04 PM, Scott Newman wrote:
>>> The way is still the same since cfront for all C++-compilers.
>
>> How many different implementation of C++ have you actually verified that
>> assumption for? Please list them.
>
> It's just the most obvious way to do it like Cfront.

So you're just assuming it, without any verification. Good luck with
that. It's the norm, not the exception, that clever people often find
reasons (sometimes good, sometimes not so good) for doing things in
in-obvious ways.

> And there is no reason to do it differently.

There's no reason that you know of. Unless you're intimately familiar
with the detailed design of many different compilers, targeting a wide
variety of different kinds of platforms, I wouldn't recommend treating
the fact that you don't know of a reason as evidence that there is no
such reason.

Scott Newman

unread,
Jun 8, 2020, 3:14:24 PM6/8/20
to
> So you're just assuming it, without any verification.

There's no reason to do it differently than Cfront.

Keith Thompson

unread,
Jun 8, 2020, 3:48:05 PM6/8/20
to
Prove it.

Note that proving your claim would require examining every existing
C++ compiler with every set of options -- and even that would not
tell us anything about a new version of some compiler released
tomorrow.

And please don't snip attribution lines from your followups.

Keith Thompson

unread,
Jun 8, 2020, 3:49:23 PM6/8/20
to
Scott Newman <sco...@gmail.com> writes:
>> So you're just assuming it, without any verification.
>
> There's no reason to do it differently than Cfront.

Thank you for confirming that you're just assuming it without any
verification.

(And please stop snipping attribution lines.)

David Brown

unread,
Jun 8, 2020, 3:50:49 PM6/8/20
to
On 08/06/2020 21:04, Scott Newman wrote:
>>> The way is still the same since cfront for all C++-compilers.
>
>> How many different implementation of C++ have you actually verified that
>> assumption for? Please list them.
>
> It's just the most obvious way to do it like Cfront.
> And there is no reason to do it differently.

Of course there are good reasons to do it differently - optimisation.
That is why any good compiler will de-virtualise calls when it can,
skipping the use of a vtable. If the compiler knows the /real/ type of
an object, then it doesn't bother looking up the vtable for a pointer to
a virtual method - it will go straight to that virtual method because it
knows that no one could possibly have changed the vtable data and this
optimisation is perfectly valid. And if it can see the definition of
the method, it can be inlined in the calling code - even though the
method is virtual.

James Kuyper

unread,
Jun 8, 2020, 4:10:05 PM6/8/20
to
Even if it were true that all implementations use exactly the same
method (which would strike me as quite unlikely even if I didn't know
that, for instance, some implementations put the pointer at the
beginning of the object, and some at the end of the object), that still
wouldn't be enough to make such code safe. Because the behavior is
undefined, implementations are free to perform optimizations based upon
the assumption that you won't do anything that stupid.

In particular, one of the most basic and common optimizations is that if
the implementation knows precisely which class's version of a virtual
member function should be called, it will call that function directly,
rather than calling it indirectly through the vtable. This not only
would result in your vtable modification sometimes being ignored, it can
also result in the confusing situation where your modification is
sometimes ignored, and sometime used.

This optimization can, for instance, be used inside the ctors and dtors
of a given class, because inside those functions, that class IS the
most-derived type, even if they're being invoked as part of the
construction of a more-derived class.
It can also be done anytime an object has a fixed type, rather than
being accessed through a pointer or a reference.
It can even be used when accessing an object through a reference or
pointer, if the implementation knows that the reference or pointer will
always refer to an object of a specific most-derived type. That can be
easy to determine if the object's definition is in the same translation
unit as the code that accesses it by reference. Some modern
implementations can even determine that at link time by looking across
two or more translation units.

That's just one optimization that I happen to know about - I'm sure
there's many others I didn't think of.

Scott Newman

unread,
Jun 8, 2020, 4:11:32 PM6/8/20
to
>> The whole thing is predictable since no compiler behaves differently
>> than cfront.

> Prove it.

There's no need to prove it. ABIs like COM f.e. rely on that.

Scott Newman

unread,
Jun 8, 2020, 4:13:30 PM6/8/20
to
> In particular, one of the most basic and common optimizations is that if
> the implementation knows precisely which class's version of a virtual
> member function should be called, it will call that function directly,
> rather than calling it indirectly through the vtable. This not only
> would result in your vtable modification sometimes being ignored, it can
> also result in the confusing situation where your modification is
> sometimes ignored, and sometime used.

Then you assign the object-address to a volatile pointer and that to
a non-volatile pointer. The compiler wouldn't be able to cache any
virtual functions across that assignemnt.

Scott Newman

unread,
Jun 8, 2020, 4:14:08 PM6/8/20
to
>> There's no reason to do it differently than Cfront.

> Thank you for confirming that you're just assuming it without any
> verification.

There's no need for verification since what I said is obvious.

StuartRedmann

unread,
Jun 8, 2020, 4:15:22 PM6/8/20
to
On 08.06.20 15:13, Frederick Gotham wrote:
>
> There is a class which has a Vtable containing the addresses of all the class's (and base classes's) virtual functions.
>
> At any given time, there might be about a dozen instances (i.e. a dozen objects) of this class in existence, and objects are continuously being created and destroyed.
>
> When a physical pin is set high (i.e. set to 3.3 volts), it will cause an interrupt to fire and so the main program will be frozen. In the interrupt routine, I want to alter one of the addresses in the class's vtable before handing control back to the main program. So from that point forward, any calls to a virtual method will call the new function whose address I have set. If the interrupt fires again in future, I will again change the vtable.
>
> Anyone ever done this before?
>
> Of course I will have to make sure that there isn't any optimisation where the compiler can predict which function will be called on the current object.
>
> The beginning of psuedo-code would be something like:
>
> extern int Some_Other_Function(int); // Defined in another file
>
> void Interrupt_Routine(void)
> {
> MyClass obj;
>
> VTable &vtable = *reinterpret_cast<Vtable*>(&obj); // std::launder?
>
> vtable.SomeFunction = SomeOtherFunction;
> }
>
> int main(void)
> {
> Register_Interrupt(PIN4, Interrupt_Routine);
>
> for ( ; /* ever */ ; )
> {
> MyClass obj;
>
> obj.SomeFunction(); // Make sure compiler doesn't hardcode func address
> }
> }

The following may work on your machine. It assumes standard vtable
layout (vtable starts at object's address), sorting of vtable entries is
not relevant as this example uses only a single virtual method:

class Base
{
public:
virtual void callme() = 0;
};

class Foo : public Base
{
public:
virtual void callme() { std::cout << "Hi, I'm Foo."; }
};

class Bar : public Base
{
public:
virtual void callme() { std::cout << "Hi, I'm Bar."; }
};

int main()
{
Foo foo;
Bar bar;

Base* base;
base = &foo;
base->callme();
base = &bar;
base->callme();

// The following results in undefined behaviour!!!
// Tested only with Apple LLVM 7.3.0, but should work with
// a number of other C++ compilers, too.
void** vtableFoo = reinterpret_cast<void**>(&foo);
void** vtableBar = reinterpret_cast<void**>(&bar);
std::swap(vtableFoo[0], vtableBar[0]);

base = &foo;
base->callme();
base = &bar;
base->callme();
}

Note that the ordering of the virtual methods in the vtable differs
greatly between compilers. IIRC, Borland C++ used to sort the methods
alphabetically, whereas MS C++ compilers used to sort them in the order
in which they appear in the class declaration. To my knowledge that was
the main reason why Borland C++ had to use the C headers for working
with COM (component object model) objects.

I trust that you are trying to reverse engineer some code, or you are
doing just some proof-of-concept stuff. As all the others have stated
quite clearly, fiddling with vtables is quite dangerous.

Regards,
Stuart

BTW: As an old Objective-C programmer I quite like the feature to change
a class'es behaviour during run-time. In contrast to C++, changing the
Objective C equivalent of a virtual method is directly supported by the
language.

Scott Newman

unread,
Jun 8, 2020, 4:15:25 PM6/8/20
to
>> It's just the most obvious way to do it like Cfront.
>> And there is no reason to do it differently.

> Of course there are good reasons to do it differently - optimisation.
> That is why any good compiler will de-virtualise calls when it can,
> skipping the use of a vtable.

Then you assign the object adress to a volatile pointer so that
the compiler is inable to say if the object behind that pointer
might have changed.

Scott Newman

unread,
Jun 8, 2020, 4:18:58 PM6/8/20
to
The issue you might run in here is that the vtable lies in a
non-writable page. So you would have to allocate a completely
new vtable, copy the contents of the old vtable there and
implant a new vtable-pointer on the objects starting adddress
(or at the address before the first data-member if the object
has derived from a class without virtual functions).
That's professional programming since this is 100% portable
and reliable.

Scott Newman

unread,
Jun 8, 2020, 4:20:52 PM6/8/20
to
> Note that the ordering of the virtual methods in the vtable differs
> greatly between compilers. IIRC, Borland C++ used to sort the methods
> alphabetically, whereas MS C++ compilers used to sort them in the order
> in which they appear in the class declaration. To my knowledge that was
> the main reason why Borland C++ had to use the C headers for working
> with COM (component object model) objects.

Not true. Borland C++ is C++-COM-compatible.

Christian Gollwitzer

unread,
Jun 8, 2020, 4:22:00 PM6/8/20
to
Am 08.06.20 um 19:40 schrieb Bonita Montero:
> Use non-virtual functions which dispatch according to your
> own virtual function tables.
+1

I think, this method is described in this talk, where you implement your
own vtable:

https://www.youtube.com/watch?v=gVGtNFg4ay0


Christian

Keith Thompson

unread,
Jun 8, 2020, 4:24:43 PM6/8/20
to
Then there's no need for anyone to reply to you. Bye.

Scott Newman

unread,
Jun 8, 2020, 4:25:31 PM6/8/20
to
>> There's no need for verification since what I said is obvious.

> Then there's no need for anyone to reply to you. Bye.

You're right.
Because I'm correct there's nothing more to say.
Bye.

Frederick Gotham

unread,
Jun 8, 2020, 4:27:40 PM6/8/20
to

I have the machine code of the program I want to alter. I don't have the original C++ code for it however I worked on it before and so I have a vague recollection of how it works.

The first thing I will do is search through the machine code for direct calls to the function which I intend to hijack (i.e. I will search for where the vtable accessing has been optimised away). I will replace these direct calls with actual use of the vtable. (There might not be any direct calls).

Next I will take the machine code of an existing interrupt routine and run it through a decompiler; I will add my own code for altering the vtable, and then I will compile the interrupt routine again and slot it back into the program. (I actually might not need to use a decompiler if I simply append my own machine code).

Testing will be very easy: It will either work or not work.

What I am proposing is an alternative to re-writing the original program, at a cost of a few thousand man-hours.

James Kuyper

unread,
Jun 8, 2020, 4:31:00 PM6/8/20
to
And if I'm not using COM?

However, if you're correct, that is important information - what
precisely does the documentation for COM say about the behavior when you
modify a vtable?

Scott Newman

unread,
Jun 8, 2020, 4:34:31 PM6/8/20
to
>> There's no need to prove it. ABIs like COM f.e. rely on that.

> And if I'm not using COM?

The compilers still have to adhere to that.

> However, if you're correct, that is important information - what
> precisely does the documentation for COM say about the behavior
> when you modify a vtable?

The virtual functions still gonna be called.

David Brown

unread,
Jun 8, 2020, 4:36:12 PM6/8/20
to
You are just inventing more and more silly, inefficient and undefined
ways to handle something that is /extremely/ simple. Use a variable and
a conditional, or a separate function pointer (according to taste), and
be done with it.


Scott Newman

unread,
Jun 8, 2020, 4:39:11 PM6/8/20
to
>> Then you assign the object adress to a volatile pointer so that
>> the compiler is inable to say if the object behind that pointer
>> might have changed.

> You are just inventing more and more silly, inefficient and undefined
> ways to handle something that is /extremely/ simple.  Use a variable and
> a conditional, or a separate function pointer (according to taste), and
> be done with it.

If you have a function-pointer in your class this would need additional
space for each function. If you modify the vtable, this wouldn't need
additional space.

James Kuyper

unread,
Jun 8, 2020, 4:40:13 PM6/8/20
to
I'm not quite sure what you mean by that. Could you give an example of
actual code which implements your suggestion? It should, ideally, be
short, complete, compilable, and executable - but if that's too
difficult for you, I'll settle for an example where everything that
needs to be declared "volatile" is so-declared, and where all the code
that relies upon the fact that it is volatile is explicitly written out.

Is that code any less complicated than simply defining a function pointer?

The code which changes the vtable renders the behavior of your entire
program undefined. As a result "this international standard imposes no
requirements" on the behavior of such code (3.27). In particular, it
does not require that your use of "volatile" be honored.


Scott Newman

unread,
Jun 8, 2020, 4:43:31 PM6/8/20
to
> I'm not quite sure what you mean by that.

void f( ClassWithVirtual *cvw )
{
cvw->vf(); // virtual
modify_vtable( cvw );
// prevent caching of method-pointers
cvw = (ClassWithVirtual *)(ClassWithVirtual *volatile)cvw;
cvw->vf(); // virtual
}

James Kuyper

unread,
Jun 8, 2020, 4:46:13 PM6/8/20
to
On 6/8/20 4:34 PM, Scott Newman wrote:
>>> There's no need to prove it. ABIs like COM f.e. rely on that.
>
>> And if I'm not using COM?
>
> The compilers still have to adhere to that.

Even compilers targeting non-Windows platforms?

>> However, if you're correct, that is important information - what
>> precisely does the documentation for COM say about the behavior
>> when you modify a vtable?
>
> The virtual functions still gonna be called.

I said "precisely" - please identify the exact document that says that,
and the exact clause in that document which says so, and the precise
wording used to say it.

If you don't already know the answer to that last question, you're a
fool for relying on the assumption that the answer supports your opinion.

Scott Newman

unread,
Jun 8, 2020, 4:49:09 PM6/8/20
to
>> The compilers still have to adhere to that.
> Even compilers targeting non-Windows platforms?

Yes, they al behave like Cfront.

> I said "precisely" - please identify the exact document that says that,
> and the exact clause in that document which says so, and the precise
> wording used to say it.

It's not the C++-standard that says that, it's reliable behaviour
of the compilers. You're really a Noob that has no clue.

Vir Campestris

unread,
Jun 8, 2020, 4:56:27 PM6/8/20
to
Up-thread people have already pointed out that some implementations put
the vtbl pointer at the end of the object.

Elsewhere it's been pointed out that the optimiser is free to bypass the
vtbl entirely if it knows where it is (ought to be) pointing.

I don't understand why you'd want to do this when a simple function
pointer would have exactly the same effect in a portable manner. And not
behave differently when you turn the optimiser on for a release build.

Andy

David Brown

unread,
Jun 8, 2020, 4:58:21 PM6/8/20
to
You must surely be trolling. But I think it must be obvious to the OP
by now that everyone in this thread with any understanding of C++ is
advising against the idea.

Vir Campestris

unread,
Jun 8, 2020, 5:01:05 PM6/8/20
to
On 08/06/2020 18:49, Mr Flibble wrote:
> On 08/06/2020 18:36, Manfred wrote:
>> On 6/8/2020 7:04 PM, Mr Flibble wrote:
>>> On 08/06/2020 14:44, David Brown wrote:
>>>>
>>>> Make a single static (probably volatile) variable in the class that
>>>> tracks which function you'll want to call.  Your virtual function -
>>>> if indeed it needs to be virtual - will check that variable to
>>>> decide what to do.  (Prefer a check on the variable followed by a
>>>> conditional or switch to using a function pointer - it's easier to
>>>> get right, and will usually be more efficient.)
>>>
>>> What century is this? Use std::atomic not volatile.
>>>
>>
>> Actually, an interrupt handler is exactly the purpose that volatile is
>> designed for: it tells the compiler that a variable may change its
>> value outside the flow of operation as seen by the compiler.
>
> Nonsense. Disable interrupts much? std::atomic is the superior solution
> for ISRs these days. Stop living in the past.
>
<snip>

If you're going to use volatile (as I would have happily 30 years ago)
you have to understand what it's going to do on your architecture with
your cache design and a bunch of other features, such as the NUMA
architecture in place.

We still use volatile to poke HW registers. We know what it does on our
platforms in that context. And it's all in the platform dependent code.

Flibble is right here; volatile is not the right mechanism for passing
data between threads; and in this context ISRs count as threads.

std::atomic is designed for that, and will do the right thing in a
portable manner.

volatile is largely obsolete.

Andy

Paavo Helde

unread,
Jun 8, 2020, 5:04:28 PM6/8/20
to
08.06.2020 23:27 Frederick Gotham kirjutas:
>
> I have the machine code of the program I want to alter. I don't have the original C++ code for it however I worked on it before and so I have a vague recollection of how it works.
>
> The first thing I will do is search through the machine code for direct calls to the function which I intend to hijack (i.e. I will search for where the vtable accessing has been optimised away). I will replace these direct calls with actual use of the vtable. (There might not be any direct calls).

Some calls may also be inlined by the optimizer, much more fun!

>
> Next I will take the machine code of an existing interrupt routine and run it through a decompiler; I will add my own code for altering the vtable, and then I will compile the interrupt routine again and slot it back into the program. (I actually might not need to use a decompiler if I simply append my own machine code).
>
> Testing will be very easy: It will either work or not work.
>
> What I am proposing is an alternative to re-writing the original program, at a cost of a few thousand man-hours.
>

This now makes more sense, as here you are working at the machine
code/assembler level. This is the level where manipulating things like
vtable is actually well defined, unlike at the C++ level.

Scott Newman

unread,
Jun 8, 2020, 5:13:52 PM6/8/20
to
> Up-thread people have already pointed out that some implementations put
> the vtbl pointer at the end of the object.

There's no such implementation.
But it might be that when you derive from a class without virtual
functions that the vtable-pointer is at the first address in the
new class, i.e. before other data-members.

> Elsewhere it's been pointed out that the optimiser is free to bypass
> the vtbl entirely if it knows where it is (ought to be) pointing.

I've shown in another post how to disable this behaviour,

> I don't understand why you'd want to do this when a simple function
> pointer would have exactly the same effect in a portable manner.

A function-pointer in the vtable is more space-efficient.

Scott Newman

unread,
Jun 8, 2020, 5:15:43 PM6/8/20
to
> You must surely be trolling.

Wrong.

> But I think it must be obvious to the OP
> by now that everyone in this thread with any understanding of C++ is
> advising against the idea.

Not necessary. There are safe, reliable and 100% portable ways to
to that what the OP wants to do. That's absolutely professional
sw-development.

Scott Newman

unread,
Jun 8, 2020, 5:18:37 PM6/8/20
to
> Flibble is right here; volatile is not the right mechanism for passing
> data between threads; and in this context ISRs count as threads.

There's one exception: you might use a volatile bool for a stop-flag.
I.e. you might f.e. say ...
while( !::stop );
... instead of ...
while( !stop.load( memory_order_relaxed );
I think the first one is more readable.

James Kuyper

unread,
Jun 8, 2020, 5:21:50 PM6/8/20
to
On 6/8/20 4:49 PM, Scott Newman wrote:
> >> The compilers still have to adhere to that.
> > Even compilers targeting non-Windows platforms?
>
> Yes, they al behave like Cfront.
>
> > I said "precisely" - please identify the exact document that says that,
> > and the exact clause in that document which says so, and the precise
> > wording used to say it.
>
> It's not the C++-standard that says that, ...

I didn't say "C++-standard" - I just said "the exact document". The
relevant document should be one that describes COM, which certainly
isn't the C++ standard.

> ... it's reliable behaviour

More accurately, it's behavior that you've decided to rely upon. Without
any document actually guaranteeing that it will actually work, relying
upon that behavior is a pretty stupid thing to do. It might fail the
very next time that you decide to rely upon it.

> of the compilers. You're really a Noob that has no clue.

On the contrary - I've been programming computers since roughly 1974,
and have been earning an income as a computer programmer since 1979. And
in all that time, one of the most common Noob errors I've seen has been
for a Noob to be familiar with only one way of doing something, and
assuming that it was the only way to do that thing. When I started out
as a programmer, the catch phrase for that error was "All the world's a
Vax". A few decades ago, it switched over to "All the world's a PC".

I don't remember ever falling into that trap. It helped that my first
three programming languages were Fortran, Basic, and APL - which
prevented me from acquiring the delusion that every language works
basically the same way. And it wasn't very long after I started
programming professionally that I had experience with Unix, PC-DOS,
Windows, CP-M, and Vax VMS, so I also avoided acquiring the delusion
that all operating systems were pretty much the same.

Scott Newman

unread,
Jun 8, 2020, 5:23:15 PM6/8/20
to
> On the contrary - I've been programming computers since roughly 1974,

Then you should have noticed that all C++-implementation behave
like I describe.

Paavo Helde

unread,
Jun 8, 2020, 5:23:21 PM6/8/20
to
08.06.2020 23:39 Scott Newman kirjutas:
>
> If you have a function-pointer in your class this would need additional
> space for each function. If you modify the vtable, this wouldn't need
> additional space.

I see during your long carrier you have not learned about the 'static'
keyword, you might want to look it up.

James Kuyper

unread,
Jun 8, 2020, 5:25:02 PM6/8/20
to
OK - what I'm looking for is a little bit more detailed than that. In
particular:

What is the declaration for vf()? This is relatively minor, I just want
to be certain what you're talking about.
What is the definition of modify_vtable()? This is the most important
part of what I was asking about.

Scott Newman

unread,
Jun 8, 2020, 5:26:41 PM6/8/20
to
>> If you have a function-pointer in your class this would need additional
>> space for each function. If you modify the vtable, this wouldn't need
>> additional space.

> I see during your long carrier you have not learned about the 'static'
> keyword, you might want to look it up.

LOL, you're so stupid !
static wouldn't help you here when you need a vtable-like per-object
dispatch.

Scott Newman

unread,
Jun 8, 2020, 5:28:53 PM6/8/20
to
Am 08.06.2020 um 23:24 schrieb James Kuyper:
> On 6/8/20 4:43 PM, Scott Newman wrote:
>>> I'm not quite sure what you mean by that.
>>
>> void f( ClassWithVirtual *cvw )
>> {
>> cvw->vf(); // virtual
>> modify_vtable( cvw );
>> // prevent caching of method-pointers
>> cvw = (ClassWithVirtual *)(ClassWithVirtual *volatile)cvw;
>> cvw->vf(); // virtual
>> }
> OK - what I'm looking for is a little bit more detailed than that. In
> particular:

> What is the declaration for vf()? This is relatively minor, I just want
> to be certain what you're talking about.

It's just a virtual function whose vtable-pointer is modified by
modify_vtable(). It's assigned to itself through a volatile pointer
to prevent caching of the vtable-entry of vf. That's professional,
reliable sw-development and you're a Noob.

James Kuyper

unread,
Jun 8, 2020, 5:33:28 PM6/8/20
to
On 6/8/20 5:13 PM, Scott Newman wrote:
>> Up-thread people have already pointed out that some implementations put
>> the vtbl pointer at the end of the object.
>
> There's no such implementation.

According to <https://en.wikipedia.org/wiki/Virtual_method_table>,

"Many compilers place the virtual table pointer as the last member of
the object; other compilers place it as the first; portable source code
works either way.[2] For example, g++ previously placed the pointer at
the end of the object.[3]"

You don't have to trust Wikipedia about that; [2] and [3] refer to the
bibliography. [3] refers to
<https://web.archive.org/web/20110725153606/http://www.codesourcery.com/public/cxx-abi/cxx-closed.html>,
which says, among other things:

" [990617 All] Given a Vptr and only non-polymorphic bases, which (Vptr
or base) goes at offset 0?

HP: Vptr at end, but IA-64 is different because no load displacement
Sun: Vptr at 0 probably preferred
g++: Vptr at end today"


Keith Thompson

unread,
Jun 8, 2020, 5:34:13 PM6/8/20
to
Even being right wouldn't justify this level of arrogance.

Scott Newman

unread,
Jun 8, 2020, 5:35:19 PM6/8/20
to
> "Many compilers place the virtual table pointer as the last member of
> the object; other compilers place it as the first; portable source code
> works either way.[2] For example, g++ previously placed the pointer at
> the end of the object.[3]"

That's not possible because the object's derived classes are growing
at the end. So this is nonsense.

Scott Newman

unread,
Jun 8, 2020, 5:37:02 PM6/8/20
to
>> It's not the C++-standard that says that, it's reliable behaviour
>> of the compilers. You're really a Noob that has no clue.

> Even being right wouldn't justify this level of arrogance.

But it is less arrogant than with being wrong !!!!

Paavo Helde

unread,
Jun 8, 2020, 5:40:27 PM6/8/20
to
What makes you think vtable is per-object?

Ian Collins

unread,
Jun 8, 2020, 5:46:41 PM6/8/20
to
On 09/06/2020 05:41, Scott Newman wrote:
>>> In most cases you only use one compiler.
>>> So in most cases there's not a problem with this.
>
>> So my conclusion is that you are a troll.
>
> No, I am a practitioner while you are a theorist.

Snipping attribution is a classic troll indicator!

--
Ian.

James Kuyper

unread,
Jun 8, 2020, 5:50:05 PM6/8/20
to
On the contrary - I've always tried to write code that avoids relying
upon anything not guaranteed by a relevant document that applies to all
contexts in which my code is intended to run. I started out relying on
K&R C, and later on the latest version of the C standard. Some of my
Windows code has, of necessity, relied upon Microsoft documentation, but
that was only for a short portion of my career. More recently, I've
relieved upon the latest versions of the C++ and POSIX standards. I've
seldom written code that was intended to be used with only one
implementation of C++. As a result, I've never had the opportunity to
notice whether or not they all behave as you describe.

But since your expectations apparently include always having the vtable
pointer at the beginning of an object, I already know for certain that
they're incorrect.

James Kuyper

unread,
Jun 8, 2020, 5:55:05 PM6/8/20
to
[3] is a citation for a link that I copied into my message. Have you
followed that link? If so, what is your explanation for that web page?
Is it some kind of elaborate hoax? For a hoax, it seems to be a pretty
elaborate one.

James Kuyper

unread,
Jun 8, 2020, 5:57:31 PM6/8/20
to
I think what he means is that each object can contain a pointer to a
different vtable. It's the pointer, not the vtable, which is per-object.

Mr Flibble

unread,
Jun 8, 2020, 6:08:35 PM6/8/20
to
EVERYTHING YOU SAY IS WRONG.

/FLIBBLE

--
"Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin

“You won’t burn in hell. But be nice anyway.” – Ricky Gervais

“I see Atheists are fighting and killing each other again, over who doesn’t believe in any God the most. Oh, no..wait.. that never happens.” – Ricky Gervais

"Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say."

Keith Thompson

unread,
Jun 8, 2020, 6:56:23 PM6/8/20
to
My own policy (which I may or may not follow 100% consistently) is that
if a post includes personal abuse, such as the above "LOL, you're so
stupid !", I will not respond to anything in that post.

I humbly suggest that this newsgroup would be improved by everyone
following a similar policy.

Richard Damon

unread,
Jun 8, 2020, 9:54:30 PM6/8/20
to
On 6/8/20 12:54 PM, Scott Newman wrote:
>> Of course you can customize the vtable this way.
>
> It would be the best to scan the vtable linearly for a known
> method-address and replace that address with the method you
> like. You can simply take a function whose first parameter
> will take the this pointer.
> There might be implementations where this won't work, but
> currently there isn't any.

One issue with this, is that depending on the exact inheritance
hierarchy, it can well be that the entry for the given function doesn't
point directly to the function, but to a 'thunk' that adjusts the object
pointer. Also, it isn't always a matter of THE vtable, but A vtable or
THE vtableS (multiple inheritance creates multiple vtables)

Paavo Helde

unread,
Jun 9, 2020, 12:11:53 AM6/9/20
to
In that case the objects would belong to different classes. And voila,
static data members defined in different classes would be different as well!

> It's the pointer, not the vtable, which is per-object.
>

OP wanted to modify a slot in a vtable.

A vtable is a class-specific data structure residing in a single place
in the program memory space (unless duplicated and/or modified by
optimizations/thunks/dynamic libraries support, and unless bypassed by
optimizations).

A static data member is a class-specific data structure residing in a
single place in the program memory space, guaranteed.

Scott Newman

unread,
Jun 9, 2020, 3:34:25 AM6/9/20
to
> What makes you think vtable is per-object?

Show me the the code you have in mind.

Scott Newman

unread,
Jun 9, 2020, 3:46:41 AM6/9/20
to
>> There's one exception: you might use a volatile bool for a stop-flag.
>> I.e. you might f.e. say ...
>>      while( !::stop );
>> ... instead of ...
>>      while( !stop.load( memory_order_relaxed );
>> I think the first one is more readable.

> EVERYTHING YOU SAY IS WRONG.

Ok, just because you say it.

Ian Collins

unread,
Jun 9, 2020, 3:52:47 AM6/9/20
to
On 09/06/2020 08:58, David Brown wrote:
> On 08/06/2020 22:39, Scott Newman wrote:
>>>> Then you assign the object adress to a volatile pointer so that
>>>> the compiler is inable to say if the object behind that pointer
>>>> might have changed.
>>
>>> You are just inventing more and more silly, inefficient and undefined
>>> ways to handle something that is /extremely/ simple.  Use a variable
>>> and a conditional, or a separate function pointer (according to
>>> taste), and be done with it.
>>
>> If you have a function-pointer in your class this would need additional
>> space for each function. If you modify the vtable, this wouldn't need
>> additional space.
>
> You must surely be trolling.

You took your time!

--
Ian.

Öö Tiib

unread,
Jun 9, 2020, 4:10:03 AM6/9/20
to
No. By C++ standard since 2011 it is data race and so all bets off
undefined behavior, demons out from your nose included but not
guaranteed.

It may be some pre-C++11 compiler or some modern that specially
documents extensions but you utterly failed to mention any of it
so all you wrote was wrong.

Scott Newman

unread,
Jun 9, 2020, 4:20:28 AM6/9/20
to
> No. By C++ standard since 2011 it is data race and so all bets off
> undefined behavior, demons out from your nose included but not
> guaranteed.

The standard doesn't matter.
We were talking about the compatibility of different implementations.

Scott Newman

unread,
Jun 9, 2020, 4:22:01 AM6/9/20
to
Here, that's industrial-strength 100% portable code:

#include <iostream>

using namespace std;

#if defined _MSC_VER
#define CC cdecl
#else
#define CC
#endif

struct S
{
// volatile to prevent any caching
virtual int CC add( int a, int b );
};

int CC S::add( int a, int b )
{
return a + b;
}

void inject( S *s )
{
auto sub = []( S *s, int a, int b ) -> int
{
return a - b;
};
int (* CC pSub)( S *, int, int ) = sub;
void **vtable = new void *;
*vtable = (void *)pSub;
*(void **)s = vtable;
}

int f( S *s, int a, int b )
{
return s->add( a, b );
}

int main()
{
S *s = new S();
cout << s->add( 1, 2 ) << endl;
inject( s );
S *volatile s2 = s;
s = s2;
cout << s->add( 1, 2 ) << endl;
}

Paavo Helde

unread,
Jun 9, 2020, 6:18:22 AM6/9/20
to
Your example contains anachronisms (warning C4229: anachronism used:
modifiers on data are ignored), an unused function (f), undefined
behavior (as we all know by now) and memory leaks. In addition, it does
not satisfy the initial desire of OP to alter the original vtable slot,
meaning that the OP obviously wanted the function to get replaced for
all objects of the class, not for a single object only.

Here is a standard-compliant version of code which does not contain UB
or memory leaks and replaces the function for all objects of the class
(can be made object-specific with trivial changes, if needed):

#include <iostream>
#include <atomic>
#include <memory>

using namespace std;

struct S {
virtual int add(int a, int b) {
return (*f)(a, b);
}
using func = int(*)(int, int);
// atomic needed if inject() is called in an interrupt handler
// or in another thread.
static atomic<func> f;
};

atomic<S::func> S::f( [](int a, int b) {return a+b;} );

template<class FUNCTOR>
void inject(FUNCTOR repl) {
S::f = repl;
}

int main() {
auto s = make_unique<S>();
cout << s->add(1, 2) << endl;
inject([](int a, int b) {return a-b;});
cout << s->add(1, 2) << endl;
}

Öö Tiib

unread,
Jun 9, 2020, 6:39:36 AM6/9/20
to
On the contrary, some versions of MSVC that give volatile Java-like
semantics because of need to compile C++/CLI that is Java-like
language do not matter. The standard is the one and only document
that defines compatibility between C++ compilers.

Scott Newman

unread,
Jun 9, 2020, 6:40:08 AM6/9/20
to
> Your example contains anachronisms (warning C4229: anachronism used:
> modifiers on data are ignored), an unused function (f), undefined
> behavior (as we all know by now) and memory leaks.

The memory-leak doen't count because this is only an example of how
it principally works.

> #include <iostream>
> #include <atomic>
> #include <memory>
>
> using namespace std;
>
> struct S {
>     virtual int add(int a, int b) {
>         return (*f)(a, b);
>     }
>     using func = int(*)(int, int);
>     // atomic needed if inject() is called in an interrupt handler
>     // or in another thread.
>     static atomic<func> f;
> };
>
> atomic<S::func> S::f( [](int a, int b) {return a+b;} );
>
> template<class FUNCTOR>
> void inject(FUNCTOR repl) {
>     S::f = repl;
> }
>
> int main() {
>     auto s = make_unique<S>();
>     cout << s->add(1, 2) << endl;
>     inject([](int a, int b) {return a-b;});
>     cout << s->add(1, 2) << endl;
> }

That's code full of UB.

Scott Newman

unread,
Jun 9, 2020, 6:40:42 AM6/9/20
to
> On the contrary, some versions of MSVC that give volatile Java-like
> semantics because of need to compile C++/CLI that is Java-like
> language do not matter. The standard is the one and only document
> that defines compatibility between C++ compilers.

C++/CLI is not C++.

Scott Newman

unread,
Jun 9, 2020, 6:42:05 AM6/9/20
to
> On the contrary, some versions of MSVC that give volatile Java-like
> semantics because of need to compile C++/CLI that is Java-like
> language do not matter. The standard is the one and only document
> that defines compatibility between C++ compilers.

And there are other features which are docuemnted in the compiler
-specification which show the compatibility. Take f.e. the #pragma
pack() comatibility of gcc.
It is loading more messages.
0 new messages