如何让gcc警告返回局部变量的地址?

使用gcc 4.4.5,我发出以下代码的警告。

 char *f(void) { char c; return &c; } 

但是,当我使用临时指针时,不再有警告(即使行为是错误的)。

 char *f(void) { char c; char *p = &c; return p; } 

我听说C中的指针分析很难,但gcc可以警告这样的代码吗?

编译器和大多数静态分析器不会尝试警告程序可能出错的一切,因为这会导致太多误报(警告与源代码中的实际问题不对应)。

Macmade在评论中推荐Clang ,我可以推荐。 请注意,Clang仍然旨在通过最大限度地减少误报来为大多数开发人员提供帮助。 这意味着它有错误的否定,换句话说,它错过了一些真正的问题(当不确定存在问题时,它可能保持沉默,而不是冒着浪费开发人员时间的假阳性)。


请注意,程序中的函数f()是否确实存在问题,这甚至是有争议的。 下面的函数h()显然很好,虽然调用代码在返回后不能使用p

 char *p; void h(void) { char c; p = &c; } 

我可以推荐的另一个静态分析器是Frama-C的价值分析 (我是开发人员之一)。 对于某些错误家族(包括悬挂指针),当在受控条件下使用时,这一点不会留下任何误报。

 char *f(void) { char c; return &c; } char *g(void) { char c; char *p = &c; return p; } $ frama-c -val -lib-entry -main g rc ... rc:11:[value] warning: locals {c} escaping the scope of g through \result ... $ frama-c -val -lib-entry -main f rc ... rc:4:[value] warning: locals {c} escaping the scope of f through \result ... 

以上只是提供信息的消息,并不意味着function必然是错误的。 我的函数h()也有一个:

 hc:7:[value] warning: locals {c} escaping the scope of h through p 

在Frama-C输出中以“assert”一词为特征的真正错误是函数调用h()然后使用p

 void caller(void) { char d; h(); d = *p; } $ frama-c -val -lib-entry -main caller hc ... hc:7:[value] warning: locals {c} escaping the scope of h through p ... hc:13:[kernel] warning: accessing left-value p that contains escaping addresses; assert(Ook) hc:13:[kernel] warning: completely undefined value in {{ p -> {0} }} (size:<32>). 

Frama-C的价值分析称为上下文敏感 。 它分析每个调用的函数h() ,以及实际传递给它的值。 它还分析了函数caller()调用h()之后的代码,其中的值实际上可以由h()返回。 这比Clang或GCC通常做的上下文不敏感分析更昂贵,但更精确。

在第一个例子中,gcc可以清楚地看到你正在返回一个不再存在的自动变量的地址。 在第二种情况下,编译器必须遵循程序的逻辑,因为p可以很容易地指向有效的东西(例如外部字符变量)。

虽然gcc不会在这里抱怨,但它会用这样的指针使用警告:

 char *f(const char *x) { char *y = x; ... } 

同样,它可以毫无疑问地看到你正在删除此定义中的’const’限定符。

检测此问题的另一个实用程序是splint(http://splint.org)。