如何在保持标准c++函数功能的同时绕过它
How to Bypass a Standard C++ Function While Maintaining Its Functionality
我正在寻找一种能够重新定义一组POSIX函数的方法,但随后通过调用原始函数结束重新定义。我的想法是,我试图创建一个层,可以限制什么操作系统的API可以调用取决于哪个"配置文件"是活跃的。这个"配置文件"决定了哪些函数集是允许的,任何未指定的都不应该使用。
例如,如果在一个配置文件中我不允许使用strcpy,我希望能够导致编译时错误(通过static_assert)或打印一些东西到屏幕上说"strcpy不允许在此配置文件中",如下面:
MY_string.h
#include <string.h>
char *strcpy(char *restrict s1, const char *restrict s2)
{
#if defined(PROFILE_PASS_THROUGH)
printf("strcpy is not allowed in this profilen");
return strcpy(s1, s2);
#elif defined(PROFILE_ERROR)
static_assesrt(0, "strcpy is not allowed in this profilen");
return 0;
#else
return strcpy(s1, s2);
#endif
}
这样在main。cpp中我就可以使用my_string。h
#define PROFILE_PASS_THROUGH
#include "MY_string.h"
int main()
{
char temp1[10];
char temp2[10];
sprintf(temp2, "Testing");
if (0 = strcpy(temp1, temp2))
{
printf("temp1 is %sn", temp1);
}
return 0;
}
现在我意识到我上面写的代码将不能正确编译,由于strcpy的重新定义,但是有没有一种方法来允许这种功能,而不玩宏或创建我自己的标准c和c++库?
-
你可以编写一个预处理器,将对标准例程的调用更改为对你自己例程的调用。这样的预处理器可能很复杂,这取决于您是否需要识别完整的c++语法来使用名称空间等来区分调用,或者您可以更随意地识别调用。
-
你可以链接到你自己的库,生成一个可重定位的对象模块,去掉已解析的名称。您的库将包含具有标准名称的例程,例如
strcpy
,它们执行您想要的任何代码并调用其他名称,例如Mystrcpy
。由它生成的对象模块然后与第二个库和标准库链接。第二个库包含具有这些名称的例程,例如Mystrcpy
,调用原始库名称strcpy
。当然,这样做的细节取决于您的链接器。目标是有这样一个链:原始代码调用strcpy
。这被解析为第一个库中的strcpy
版本。该版本调用Mystrcpy
。Mystrcpy
调用标准库strcpy
-
您可以编译成汇编并编辑汇编中的名称,以便调用您的例程而不是标准库例程。
-
在某些系统上,您可以使用
dlsym
和<dlfcn.h>
中定义的其他函数来加载包含标准实现的动态库,并通过dlsym
返回的指针来调用它们,而不是使用源代码中的常用名称。 -
GCC连接器有一个
--wrap
开关,它将对foo
的调用解析为您的例程__wrap_foo
,并将对__real_foo
的调用(您将在实现中使用)解析为实际的foo
。
参见在Windows、UNIX和Macintosh OS X平台上拦截任意函数。
不,不能在c++中完成。您想要的更类似于LISP(或派生)语言,在那里您可以抓住现有函数的插槽并"在适当的位置覆盖它",可能会退回到原始实现。
典型的做法是在Unix上通过LD_PRELOAD,示例(Unix)下面代理一个函数调用,特别是malloc(完整示例):
/**
* malloc() direct call
*/
inline void * libc_malloc(size_t size)
{
typedef void* (*malloc_func_t)(size_t);
static malloc_func_t malloc_func = (malloc_func_t) dlsym(RTLD_NEXT, "malloc");
return malloc_func(size);
}
在你MY_String.h
:
... blah blah
using mynamespace::strcpy;
#endif // header guard or maybe not there if using pragma
则所有没有以std::为前缀的strcpys将使用您的。如果你真的想禁止他们,当你找到使用霰弹枪的人时,带上一把霰弹枪。
如果使用一些最新的GCC(例如4.7或更新的版本),您也可以在MELT中编写一个GCC 插件或GCC扩展来替换每个对strcpy
的调用到您自己的mystrcpy
。这可能会花费您一些工作(可能是几天,而不是几个小时),但是在编译器内部,在GCC编译器的内部表示(Gimple)上工作具有巨大的优势。因此,即使在内联之后也会这样做。并且由于您扩展了编译器,您可以根据需要定制它的行为。
MELT是扩展GCC的领域特定语言。
您无法避免调用这些函数。
C++
程序可以做任何它想做的事情,它可以有一些代码从libc加载strcpy
符号并运行它。如果恶意的开发人员想要调用该函数,您将无法避免。要做到这一点,您需要在一些特殊的环境中运行c++代码(在沙盒或虚拟机中),但恐怕这样的技术是不可用的。
如果你信任开发人员,并且你只是在寻找一种方法来提醒他们不要调用某些函数,那么可能会有一些解决方案。
一种解决方案可能是避免使用#include
libc头文件(如cstring
),并且只包含您自己的头文件,仅声明所需的函数。
另一个解决方案可能是查看编译后的可执行文件,以便找出调用了哪些函数,或者查看LD_PRELOAD
——一个重新定义(并因此覆盖)标准函数以使其在运行时打印警告的库。
如何修改MY_string.h
#include <cstring>
namespace my_functions{
char *strcpy(char *s1, const char *s2)
{
#if defined(PROFILE_PASS_THROUGH)
printf("strcpy is not allowed in this profilen");
return std::strcpy(s1, s2);
#elif defined(PROFILE_ERROR)
static_assert(0, "strcpy is not allowed in this profilen");
return 0;
#else
return std::strcpy(s1, s2);
#endif
}
}
using namespace my_functions;
要使其工作,您不能包含或使用命名空间std;
- C++:函数外部的超时功能
- 我在 C++ 中创建了一个函数来递归反转字符串,但是之后如何使功能打印一个 endl?
- 设计模式,以避免不必要地添加抽象函数以适应新功能
- 当我链接两个静态C++库时,我可以在两个主函数库中有两个主要功能吗?
- 具有C++迭代器参数的多功能函数
- 错误:调用'strcmp'没有匹配函数(尝试设置显示用户信息功能)
- 我有模板功能.通过使用函数std::for_each,用这个容器中的最大数字替换每个正数
- 是否有一个Windows驱动程序函数可以执行Windows文件api SeFileAttributes的等效功能
- 自定义 {fmt} 格式化函数,具有编译时格式字符串检查功能
- 如何在带有初始值设定项的构造函数中使用 vprintf/cstdarg 功能?
- =删除用户定义的成员功能,除了构造函数,分配运算符C 11
- 如何使用结构内的功能指针调用私有函数
- C 函数调用包装器包含类成员功能作为模板参数
- 您如何在与打开窗口的功能的不同函数中使用Draw函数
- 当使用嵌套类功能时,使用非静态数据成员的使用无效,但是当函数未固定时可以
- 如果我具有调用其其他实例之一的超载函数,它是否被认为是递归功能
- 使用具有返回功能的函数
- 如何在不接触函数本身的情况下暂停和恢复 C++11 std::thread 的功能
- 将带捕获功能的 lambda 传递给模板化函数
- 获取模板功能函数返回类型的功能类型