Is it possible to replace a method at runtime?

2019-02-25 11:07发布

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.

8条回答
Bombasti
2楼-- · 2019-02-25 11:32

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

查看更多
Viruses.
3楼-- · 2019-02-25 11:35

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++).

查看更多
时光不老,我们不散
4楼-- · 2019-02-25 11:35

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?

查看更多
我只想做你的唯一
5楼-- · 2019-02-25 11:36

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)

查看更多
Anthone
6楼-- · 2019-02-25 11:36

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.

查看更多
冷血范
7楼-- · 2019-02-25 11:42

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.

查看更多
登录 后发表回答