我怎样才能防范'如果传递了错误的参数类型,则用C编写的回调函数

时间:2014-06-23 15:24:34

标签: c pointers types signals

我有一个用C编写的回调函数,它在服务器上运行并且必须是防撞证明。也就是说,如果期望一个整数并传递一个字符串指针,我必须在函数内部确定,并防止在尝试对不正确的参数类型执行不允许的操作时出现Segmentation错误。

函数原型是:

void callback_function(parameter_type a, const b);

和'a'应该通过枚举告诉我'b'是整数还是字符串指针。 如果调用函数程序员犯了一个错误,并在'a'中告诉我'b'是一个整数,并且'b'实际上是一个字符串指针,那么如何在不崩溃回调函数代码的情况下确定它。这在服务器上运行,如果调用者函数出错,必须继续运行。

代码必须是C语言,并且是可移植的,因此不可能使用C库扩展。编译器是:gcc v4.8.2 平台上的整数大小为4,字符指针的长度也是4。 整数可以在数字上与字符指针具有相同的值,反之亦然。

如果我认为我得到一个字符指针而不是它,当我试图找到它的内容时,我当然会得到一个分段错误。

如果我写一个信号处理程序来处理故障,我现在如何“清除”信号,并在理智的地方恢复执行?

我是否提到'b'是一个定义为的联盟:

union param_2 {
  char * c;
  int i;
} param_to_be_passed;

我认为就是这样。

感谢您的回答。

6 个答案:

答案 0 :(得分:1)

这是不可能的。

没有办法"看" at指针并确定它是否有效取消引用,但NULL除外 - 当然要检查它。

除此之外,没有神奇的方法可以知道指针是指向字符数据,整数,函数还是其他任何东西。

答案 1 :(得分:1)

你正在寻找黑客。

什么提议来了,不要在生产中使用这些东西。

如果需要后期绑定,请采用不同的,自动防故障方法。

答案 2 :(得分:0)

如果您正在为嵌入式设备编写代码,您可能希望所有变量都驻留在RAM中。例如,从地址0x200000000x20020000可能有128 kB的RAM。如果你传递了一个指向没有这个范围的内存地址的指针,关于c,除了检查一个NULL地址之外,这将是另一种确定错误的方法。

if((a == STRING) && ((b.c == NULL) || (b.c < 0x20000000) || (b.c > 0x20020000)))
    return ERROR;

如果您在多线程环境中工作,您可以更进一步,并且要求传递给callback_function的所有地址都来自某个线程的内存空间(堆栈)。

答案 3 :(得分:0)

C中的运行时类型检查实际上是不可能的。

调用者负担正确传递数据;没有(好的,标准的,可移植的)方式来确定b是否包含正确类型的数据(即,调用者没有将指针值作为整数传递给你,反之亦然)。 / p>

我唯一可以建议的是创建两个单独的回调,其中一个回调采用int而另一个采用char *,并且在编译时将负担放在编译器上进行类型检查。

答案 4 :(得分:0)

注意:这实际上并没有尝试使该功能“防崩溃”,因为我怀疑那是不可能的。

如果允许您更改API,一个选项可能是组合联盟仅使用api来访问该类型。

typedef enum Type { STRING, INT } Type;
typedef struct StringOrInt {
    Type type;
    union { int i; char* s } value;
} StringOrInt;

void soi_set_int(StringOrInt* v, int i) {
     v->type = INT;
     v->value.i = i;
}

void soi_set_string(StringOrInt* v, char* s) {
     v->type = STRING;
     v->value.s = s;
}

Type soi_get_type(StringOrInt cosnt* v) {
     return v->type;
}

int soi_get_int(StringOrInt const* v) {
     assert(v->type == INT);
     return v->value.i;
}

char* soi_get_string(StringOrInt const* v) {
     assert(v->type == STRING);
     return v->value.s;
}

虽然这实际上并没有使其成为防撞证明,但API的用户会发现使用API​​比手动更改成员更方便,从而大大减少了错误。

答案 5 :(得分:0)

如果来电者在a中说结果为int,则不会有很大的崩溃风险,因为:

  • 在你的情况下,两种类型都有相同的长度(请注意,这不保证是便携式的!)

  • C标准说(ISO - sect.6.3.2.3):“任何指针类型都可以转换为整数类型。除了之前指定的,结果是实现定义的。如果结果无法表示在整数类型中,行为未定义。

  • 但幸运的是,大多数32位值都是有效整数。

请记住,在最坏的情况下,价值可能毫无意义。因此,您可以通过系统地验证值的一致性来避免崩溃(例如,如果使用整数来对某些数组元素进行处理,请执行绑定控件)

如果调用者在“a”中说结果是指针但是提供了int,则以可移植的方式避免崩溃要困难得多。

  • 标准ISO说:整数可以转换为任何指针类型。除非先前指定,否则结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。

  • 实际上,大多数这些错误都会被系统级别非常低的内存访问异常所困。正在实现的行为定义,没有可行的方法。