I can call a function imported with dlsym() with a wrong signature, why?

故事扮演 提交于 2020-08-09 09:36:59

问题


host.cpp has:

int main (void)
{
    void * th = dlopen("./p1.so", RTLD_LAZY);
    void * fu = dlsym(th, "fu");

    ((void(*)(int, const char*)) fu)(2, "rofl");

    return 0;
}

And p1.cpp has:

#include <iostream>

extern "C" bool fu (float * lol)
{
    std::cout << "fuuuuuuuu!!!\n";
    return true;
}

(I intentionally left errors checks out)

When executing host, “fuuuuuuuu!!!” is printed correctly, even though I typecasted the void pointer to the symbol with a completely different function signature.

Why did this happen and is this behavior consistent between different compilers?


回答1:


Because there's no information about function signature in void pointer. Or any information besides the address. You might get in trouble if you started to use parameters, tho.




回答2:


This happened because UB, and this behaviour isn't consistent with anything, at all, ever, for any reason.




回答3:


This actually isn't a very good example of creating a case that will fail since:

  1. You never use the arguments from the function fu.
  2. Your function fu has less arguments (or the activation frame itself is smaller memory-footprint-wise) than the function pointer-type you're casting to, so you're never going to end-up with a situation where fu attempts to access memory outside its activation record setup by the caller.

In the end, what you're doing is still undefined behavior, but you don't do anything to create a violation that could cause issues, so therefore it ends up as a silent error.

is this behavior consistent between different compilers?

No. If your platform/compiler used a calling convention that required the callee to clean-up the stack, then oops, you're most likely hosed if there's a mis-match in the size of the activation record between what the callee and caller expect... upon return of the callee, the stack pointer would be moved to the wrong spot, possibly corrupting the stack, and completely messing up any stack-pointer relative addressing.




回答4:


It's just happened, that

  • C uses cdecl call conversion (so caller clears the stack)
  • your function does not use given arguments arguments

so your call seems to work correctly.

But actually behavior is undefined. Changing signature or using arguments will cause your program crash:

ADD:

For example, consider stdcall calling conversion, where callee mast clear the stack. In this case, even if you declare correct calling conversion for both caller and callee, your program will still crash, because your stack will be corrupted, due to callee will clear it according to it signature, but caller fill according another signature:

#include <iostream>
#include <string>

extern "C" __attribute__((stdcall)) __attribute__((noinline)) bool fu (float * lol) 
{
    std::cout << "fuuuuuuuu!!!\n";
    return true;
}

void x()
{
    (( __attribute__((stdcall)) void(*)(int, const char*)) fu)(2, "rofl");
}

int main (void)
{
    void * th = reinterpret_cast<void*>(&fu);

    std::string s = "hello";

    x();

    std::cout << s;

    return 0;
}


来源:https://stackoverflow.com/questions/12572575/i-can-call-a-function-imported-with-dlsym-with-a-wrong-signature-why

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!