中毒某些API函数(不是维护者)

Dam*_*mon 11 c++

与例如: 如何在VC++中毒化标识符?
在C++中"毒化一个函数"是什么意思?

有没有办法"正确"毒化一些声明(或实现)不受我控制的函数?

具体来说,我试图阻止某些Windows API函数的使用可能导致意外结果,例如CreateFileA(使用T宏隐藏了混合ANSI和Unicode的事实)或SetWindowLong(这将导致您的程序无声地失败,没有错误,也没有机会知道64位系统出了什么问题).

我对"正确"中毒的定义是,试图调用该函数会破坏构建时出现可读错误(如果错误发生在源代码中的正确位置,则奖励积分).
优选地,这应该是便携式的,并且至少它必须与GCC和clang一起工作.

到目前为止我尝试/看过的内容:

预处理器

最简单,最明显的解决方案是利用预处理器:

#define CreateFileA __poison_ANSI_CreateFileA
Run Code Online (Sandbox Code Playgroud)

这对于一个特定的函数以及其他几个函数非常有效,完全按照预期工作,具有提示问题的精确错误并指向源中的正确位置:

error: no matching function for call to '__poison_ANSI_CreateFileA'
note: expanded from macro 'CreateFile'
note: expanded from ... (precise location in source)
Run Code Online (Sandbox Code Playgroud)

对于不同的功能,每个人都需要有一个唯一的名称,以避免冲突的定义错误,这是繁琐但容易完成的.到目前为止一切那么好,除了它不适用于MinGW-w64标头本身使用可变参数宏篡改名称的函数,例如CreateWindowSetWindowLong.无论如何,这些编译得很好,中毒与否.

编译

#pragma GCC poison铿锵碰巧也理解了(并且还有自己的版本),外观和声音应该完全符合我的要求,并以最惯用的方式.唉,它不起作用.或者说,它运作得太好了.
当中毒名称出现在声明中时,使用pragma指令中毒的函数已经触发错误,这意味着... 每次都在包含标题的每个构建中.这对编写程序没有多大帮助!

属性

这些都有一个巨大的缺点,你必须完全复制类型定义,以免在合法的调用上出现"模糊函数调用"错误.另一方面,它们不起作用.clang抱怨__attribute__((__error__))但忽略gnu::__error__gnu::error同样gnu::deprecated.此外,标准[[deprecated]]都很好,但似乎没有什么(编译好,甚至没有警告?!).

有什么我能做的吗?

pax*_*blo 0

我会将预处理器黑客作为第一道防线,因为它似乎可以很好地捕获某些情况,为您提供源代码中的确切位置。

我还会设置第二层防御,确保您提供一个目标文件,其中包含您想要中毒的函数的体,例如:

HWND WINAPI CreateWindowEx(DWORD dwExStyle, LPCTSTR lpClassName,
    LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth,
    int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
    LPVOID lpParam)
{
    std::cerr << "Attempting to use poisoned function CreateWindowEx\n";
    exit(1);
}
Run Code Online (Sandbox Code Playgroud)

如果您将其链接为目标文件(不是库,因为库只会链接到未解析的引用),则会出现三种可能的情况(一旦它通过了标头中毒):

  • 您的目标文件和实际代码都将被链接,您将在链接时看到重复的定义。
  • 只有您的目标文件被链接(不是真正的文件),因此,当您调用它时,您将收到错误消息并终止。这应该在测试时很早就发现。不是按照您的要求在编译/链接期间进行,但希望在发货之前进行。
  • 仅链接您的目标文件,而您调用它。在这种情况下,您浪费了一点代码空间,但您的可执行文件将运行良好。

就这样做而言,单个poisoned.hpoisoned.c应该可以解决问题,您只需确保将您想要中毒的所有功能都添加到两者中即可。

现在我还没有测试过这个方法是否适用于 MinGW,但值得一试,因为在最低级别,它需要在某个时刻调用真正的Windows 函数。

我可以预见您的 MinGW 问题发生的唯一方法是它调用一些已编译的 MinGW 对象,这些对象最终调用 Windows 函数。如果发生这种情况,那么链接器捕获也应该捕获它。