3

假设有一个库函数(不能修改),它接受一个回调(函数指针)作为它的参数,它将在将来的某个时候被调用。我的问题:有没有办法将额外的数据与函数指针一起存储,以便在调用回调时,可以检索额外的数据。该程序在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));
    // ...
}

问题是因为callback_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
}

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

4

1 回答 1

2

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

我首先将错误报告给图书馆的作者。每个人都应该知道最好不要提供没有私有数据参数的回调接口。

有这样的限制会让我三思而后行图书馆是否是可重入的。我建议确保您一次只能有一个未完成的呼叫,并将回调参数存储在全局变量中。

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

于 2013-06-23T10:13:00.237 回答