检查通过函数指针调用的函数是否有 return 语句

Check whether function called through function-pointer has a return statement

我们有一个插件系统,它通过 dlopening/LoadLibrarying dll/so/dylib 然后 dlsyming/GetProcAddressing 函数调用 dll(用户生成的插件)中的函数,然后将结果存储在函数指针。

不幸的是,由于一些错误的示例代码被复制粘贴,这些 dll 中的一些在野外没有正确的函数签名,并且不包含 return 语句。

一个 dll 可能包含这个:

extern "C" void Foo() { stuffWithNoReturn(); } // copy-paste from bad code

或者它可能包含:

extern "C" int Foo() { doStuff(); return 1; } // good code

加载 dll 的应用程序依赖于 return 值,但是有大量 dll 没有 return 语句。我正在尝试检测这种情况,并警告用户他的插件存在问题。

这段天真的代码应该可以解释我要做什么:

typedef int (*Foo_f)(void);
Foo_f func = (Foo_f)getFromDll(); // does dlsym or GetProcAddress depending on platform
int canary = 0x42424242;
canary = (*func)();
if (canary == 0x42424242)
   printf("You idiot, this is the wrong signature!!!\n");
else
   real_return_value = canary;

不幸的是,这不起作用,金丝雀在调用具有已知缺陷的 dll 后包含一个随机值。我天真地假设调用一个没有 return 语句的函数会使金丝雀完好无损,但事实并非如此。

我的下一个想法是编写一些内联汇编程序来调用该函数,并在 return 上检查 eax 寄存器,但是 Visual Studio 2015 不允许 __asm () 不再是 x64 代码。

我知道对此没有符合标准的解决方案,因为将函数指针强制转换为错误的类型当然是未定义的行为。但是,如果有人有至少在 64 位 Windows 上使用 Visual C++ 的解决方案,或者在 MacOS 上使用 clang 的解决方案,我将非常高兴。

@Lorinczy Zsigmond 是正确的,如果函数执行某些操作但 return 什么都不做,则寄存器的内容是未定义的。 然而,我们发现在实践中,return nothing 的插件几乎总是空函数,这些函数编译为 retn 0x0 并保持 return 寄存器不变。我们可以通过使用已知值 (0xdeadbeef) 喷射 rax 寄存器并检查它来检测这种情况。