我正在寻找一种方法来重新定义一组POSIX函数,然后通过调用原始函数结束重新定义。我的想法是,我正在尝试创建一个可以限制可以调用OS 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 profile\n");
return strcpy(s1, s2);
#elif defined(PROFILE_ERROR)
static_assesrt(0, "strcpy is not allowed in this profile\n");
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 %s\n", temp1);
}
return 0;
}
现在我意识到由于strcpy的重新定义,我上面编写的代码将无法正确编译,但有没有办法允许这种功能而无需使用宏或创建我自己的标准c和c ++库?
答案 0 :(得分:3)
您可以编写一个预处理器来更改对标准例程的调用,以调用您自己的例程。这样的预处理器可能很复杂,这取决于您是否需要识别完整的C ++语法来区分使用名称空间的呼叫等等,或者您可以通过更随意地识别呼叫来逃避。
您可以链接到您自己的库,生成一个可重定位目标模块,其中已解析名称被剥离。您的库将包含具有标准名称的例程,例如strcpy
,它们可以执行您想要的任何代码并调用其他名称,例如Mystrcpy
。然后,由此生成的对象模块与第二个库和标准库链接。第二个库包含具有这些名称的例程,例如Mystrcpy
,它们调用原始库名strcpy
。执行此操作的详细信息当然取决于您的链接器。目标是建立一个这样的链:原始代码调用strcpy
。这已解析为第一个库中strcpy
的版本。该版本调用Mystrcpy
。 Mystrcpy
调用标准库strcpy
。
您可以编译汇编并编辑程序集中的名称,以便调用例程而不是标准库例程。
在某些系统上,您可以使用dlsym
和<dlfcn.h>
中定义的其他函数来加载包含标准实现的动态库,并通过{{1}返回的指针调用它们而不是源代码中的通常名称。
GCC链接器有一个dlsym
开关,用于解析--wrap
对您的例程foo
的调用,并解析对__wrap_foo
的调用(您将在实施)到真实的__real_foo
。
另见Intercepting Arbitrary Functions on Windows, UNIX, and Macintosh OS X Platforms。
答案 1 :(得分:0)
不,不能用C ++完成。你想要的更像是一种LISP(或衍生)语言,你可以抓住现有函数的插槽并“覆盖它”,可能会回到最初的实现。
答案 2 :(得分:0)
在Unix上的典型做法是通过LD_PRELOAD,示例(Unix)代理函数调用,特别是malloc(full example):
/**
* 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);
}
答案 3 :(得分:0)
在MY_String.h
:
... blah blah
using mynamespace::strcpy;
#endif // header guard or maybe not there if using pragma
然后所有没有以std ::为前缀的strcpys将使用你的。如果你真的想要禁止它们,那么当你找到使用它的人时,请用它来霰弹枪。
答案 4 :(得分:0)
如果使用最新的GCC(例如4.7或更新版本),您还可以在MELT中编写GCC 插件或 GCC扩展程序来替换每个电话到strcpy
到mystrcpy
。这可能会带给你一些工作(可能是几天,而不是几小时),但在GCC编译器的内部表示(Gimple)中,在编译器内工作具有巨大的优势。所以即使在内联等之后它也会完成。并且由于你扩展了编译器,你可以根据你的需要定制它的行为。
MELT是一种扩展GCC的领域特定语言。它专为此类任务而设计。
答案 5 :(得分:0)
你无法避免调用这些函数。
C++
程序可以做任何想做的事情,它可能有一些代码从libc加载strcpy
符号并运行它。如果恶意开发人员想要调用该函数,则无法避免它。要做到这一点,你需要在一些特殊环境(沙箱或虚拟机)中运行C ++代码,但我担心这种技术不可用。
如果您信任开发人员,并且您只是想找到一种方法来提醒他们不要调用某些功能,那么可能会有一些解决方案。
一种解决方案可能是避免使用#include
libc标头(例如cstring
),并且只包含您自己的头文件,其中您只声明了所需的函数。
另一种解决方案可能是查找已编译的可执行文件以查找调用的函数,或者LD_PRELOAD
一个库,它重新定义(并因此覆盖)标准函数以使它们在运行时打印警告
答案 6 :(得分:0)
您将如何更改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 profile\n");
return std::strcpy(s1, s2);
#elif defined(PROFILE_ERROR)
static_assert(0, "strcpy is not allowed in this profile\n");
return 0;
#else
return std::strcpy(s1, s2);
#endif
}
}
using namespace my_functions;
为此,您无法包含或使用名称空间std;