Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在c函数指针中存储额外数据_C_Function Pointers - Fatal编程技术网

在c函数指针中存储额外数据

在c函数指针中存储额外数据,c,function-pointers,C,Function Pointers,假设有一个库函数(不能修改)接受回调(函数指针)作为其参数,该参数将在将来某个时候调用。我的问题是:有没有一种方法可以将额外的数据与函数指针一起存储,以便在调用回调时可以检索额外的数据。这个程序是用c语言编写的 例如: // callback's type, no argument typedef void (*callback_t)(); // the library function void regist_callback(callback_t cb);

假设有一个库函数(不能修改)接受回调(函数指针)作为其参数,该参数将在将来某个时候调用。我的问题是:有没有一种方法可以将额外的数据与函数指针一起存储,以便在调用回调时可以检索额外的数据。这个程序是用c语言编写的

例如:

// callback's type, no argument
typedef void (*callback_t)();  

// the library function            
void regist_callback(callback_t cb);       

// store data with the function pointer
callback_t store_data(callback_t cb, int data);

// retrieve data within the callback
int retrieve_data();

void my_callback() {
    int a;
    a = retrieve_data();
    // do something with a ...
}

int my_func(...) {
    // some variables that i want to pass to my_callback
    int a;

    // ... regist_callback may be called multiple times
    regist_callback(store_data(my_callback, a));
    // ...
}
问题是因为回调\u t不接受任何参数。我的想法是每次生成一小段asm代码填充到regist_callback中,当它被调用时,它可以找到真正的回调及其数据并将其存储在堆栈(或一些未使用的寄存器)上,然后跳转到真正的回调,并在回调中找到数据

伪代码:

typedef struct {
    // some asm code knows the following is the real callback
    char trampoline_code[X]; 
    callback_t real_callback;
    int data;       
} func_ptr_t;

callback_t store_data(callback_t cb, int data) {
    // ... malloc a func_ptr_t
    func_ptr_t * fpt = malloc(...);

    // fill the trampoline_code, different machine and
    // different calling conversion are different
    // ...

    fpt->real_callback = cb;
    fpt->data = data;

    return (callback_t)fpt;
}

int retrieve_data() {
    // ... some asm code to retrive data on stack (or some register)
    // and return
}

这合理吗?以前有没有针对此类问题做过任何工作?

不幸的是,随着时间的推移,您可能会被禁止在越来越多的系统中执行蹦床,因为执行数据是利用安全漏洞的一种非常常见的方式

我首先向库的作者报告这个bug。每个人都应该知道不要提供没有私有数据参数的回调接口

有了这样的限制,我会再三考虑库是否可重入。我建议确保一次只能有一个未完成的调用,并将回调参数存储在全局变量中


如果您认为该库适合使用,那么您可以通过编写不同的回调蹦床来扩展它,每个回调蹦床引用自己的全局数据,并将其封装在一些管理API中。

为什么不让
存储\u date()
在全局映射中存储原始函数的地址以及对
a
的引用,并通过
retrieve\u data()
将其检索?如果多次注册同一回调,则在调用回调时,它不知道是哪一个。是的,实际上,这种方法无法涵盖此用例。但是,您可以通过为每个同时注册的实例实现包装器来解决这个问题。或者只使用cb函数地址中一些未使用的低(甚至高)阶位来添加子索引…-8字节指针是宽的;-)好的,如果你没有被禁止执行你的结构,你的程序集蹦床只需要执行一次对你真正的处理器的调用。然后,您的处理程序可以检查调用的返回地址以找出结构的位置。您是指jmp吗?或者打个电话?哈,我想我知道怎么做;)