7

I want to make a plugin system with the capability to override a method at runtime.

Some answers say function pointers, but how about a defined function or class?

Like this:

class foo
{
  public:
    bar(int foobar);
}

Is there a way to get function pointer for that, or replace it?

BTW, hooking is not considered an answer because it's very platform specific and dangerous.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
Tatsuyuki Ishi
  • 3,883
  • 3
  • 29
  • 41
  • 7
    C and C++ are different languages. – Yu Hao Apr 15 '15 at 08:41
  • 1
    It is possible, and it is platform specific. It is used for example in Linux kernel (ksplice). It is more related to executable format than to a language. PS: what do you want to achieve? – ibre5041 Apr 15 '15 at 08:43
  • 1
    @ibre5041: The Linux kernel doesn't use C++, which greatly simplifies things. For instance, no (operator) overloading. – MSalters Apr 15 '15 at 12:15

8 Answers8

9

To make a plugin system you don't need to replace a method of a class at runtime.

You can replace what the method does by using polymorphism or any other way to configure an object.

Check out the answers to the following question: What's safe for a C++ plug-in system?

Community
  • 1
  • 1
Dmitry Ledentsov
  • 3,620
  • 18
  • 28
8

Runtime function "replacement" can be achieved with one of several techniques:

  1. Polymorphism
  2. Standard library facilities such as std::function
  3. Third party libraries or platform specific techniques to translate or dispatch function calls.

On which option is better is highly dependent on the intended use and target environments. For example; plugin systems could well make use of polymorphism (with the appropriate factories and possibly even combined with the template method pattern) whilst internal function routing could use std::function.

These techniques wouldn't really "replace" any of the functions, but rather can be set up at runtime to route the function call as required.

Note I've focused on the C++ aspects of the question (it was tagged C and C++ but the sample code is C++).

Niall
  • 30,036
  • 10
  • 99
  • 142
6

While you can't directly replace a method, this can be solved with another layer of indirection.

#include <iostream>
#include <functional>

class Foo
{
private:
    void default_bar(int value)
    {
        std::cout << "The default function called\n";
    }
    std::function<void(Foo*, int)> the_function = &Foo::default_bar;
public:
    void replace_bar(std::function<void(Foo*, int)> new_func)
    {
        the_function = new_func;
    }
    void bar(int value)
    {
        the_function(this, value);
    }
    void baz(int value)
    {
        std::cout << "baz called\n";
    }
};

void non_member(Foo* self, int value)
{
    std::cout << "non-member called\n";
}

int main()
{
    Foo f;
    f.bar(2);
    f.replace_bar(&Foo::baz);
    f.bar(2);
    f.replace_bar(non_member);
    f.bar(2);
    f.replace_bar([](Foo* self, int value){ std::cout << "Lambda called\n"; });
    f.bar(2);
}

Currently this replaces the method of the instance. If you want to replace the method of a class, make the_function static (even better, make it a static method returning a static variable to avoid static initialization order fiasco)

milleniumbug
  • 15,379
  • 3
  • 47
  • 71
2

Back to the original question: "Is it possible to replace a method at runtime in C/C++" it is possible and there are some use-cases for it, yet (as others have said) most of these use cases don't apply to you. This is also not very straightforward.

For example linux kernell can use something called kpatch or kGraft. This is quite complicated mechanism --- which is of course not very portable, and not very usable in userspace programs, as these techniques rely on mechanisms baked into linux kernell.

jb.
  • 23,300
  • 18
  • 98
  • 136
1

C does not have any methods (only functions), so your question is meaningless in C.

In C++11, assuming the method to be changed is virtual, and assuming your C++ implementation is using a vtable pointer located at start of the object (this is often the case with GCC on Linux), and if both old and new classes have the same size and are using single inheritance from a common base class (e.g. FooBase), you could use the placement new operator, so in your main program:

class FooBase {
   virtual ~FooBase();
   virtual int bar(int); 
   /// etc
}

class ProgramFoo : public FooBase {
 virtual ~ProgramFoo();
 virtual int bar (int);
 /// other fields and methods
};

and in your plugin:

class PluginFoo : public FooBase {
 virtual ~ProgramFoo();
 virtual int bar (int);
 /// other fields and methods
 static_assert(sizeof(PluginFoo) == sizeof(ProgramFoo), 
               "invalid PluginFoo size");
};

then you might have some plugin function like

extern "C" FooBase*mutate_foo(ProgramFoo*basep)
{
   basep->~ProgramFoo(); // destroy in place, but don't release memory
   return new(basep) PluginFoo(); // reconstruct in same place
}

it hopefully would override the old vptr by the new one.

but this smells bad, is probably undefined behavior according to the C++11 standard, but might work on some C++ implementations, and is certainly implementation specific. I don't recommend coding that way, even if it might sometimes happen to "work".

The idiomatic way would be to use member function pointers or C++11 closures.

It looks like your plugin architecture is wrongly designed. Look into Qt plugins for some good inspiration.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
1

also look at MSVC compile option /hotpatch. This will create a code, where each non-inlined method starts with an instruction having at least 2 bytes (short jmp relative 0 - i.e. NOP). Then you can rewrite image of your running application and you can store long jmp onto your new version of your method.

See Create Hotpatchable Image.

Also for example on Linux you have(long time ago had) two function called "fopen". One of them was defined on library glibc and the other one was defined in libpthread. The later one was thread-safe. And when you dlopen-ed libpthread, the "jumper" onto "fopen" function gets overwritten, and a function from libpthread gets used.

But it really depends on your goal.

ibre5041
  • 4,903
  • 1
  • 20
  • 35
  • And with `/ob0`, inlining is turned off so each method can be hotpatched. Downside: `vector::operator[ ]` will be hot-patchable too, which probably isn't what you wanted. – MSalters Apr 15 '15 at 12:21
0

On Unix systems (e.g. Linux), dlsym is very useful for loading functions or entire libraries at runtime in C/C++. See e.g. http://www.tldp.org/HOWTO/C++-dlopen/thesolution.html

Erik Alapää
  • 2,585
  • 1
  • 14
  • 25
-1

I guess it is not possible for C/C++.

The function code has been compiled to binary, you cannot change it dunning run-time.

I think interpretative languages are good at it.

fding
  • 424
  • 1
  • 5
  • 18