防止本地指针

5
也许这是一个新手问题,但在C/C++中是否有一种方法可以防止函数接受指向局部变量的指针?
考虑以下代码:
int* fun(void)
{
 int a;
 return &a;
}

编译器会生成一个警告,指针不能被返回。现在考虑这个例子:
int* g;

void save(int* a)
{
 g = a;
}

void bad(void)
{
 int a;
 save(&a);
}

这段代码会通过编译器而没有任何警告,这很不好。有没有什么属性或者类似的东西可以防止这种情况发生?比如说:
```csharp [DisallowUninitialized] int myInt; ```
void save(int __this_pointer_must_not_be_local__ * a)
{
 g = a;
}

如果有人知道答案,提前感谢。


1
代码审查?...像lint这样的代码分析工具? - Mitch Wheat
代码审查,静态分析。你所要求的实际上非常非常复杂。 - user703016
1
如果我想这样做void f() { int b; save(&b); /* do stuff */ save(NULL); }怎么办?并不一定是变量“本地”很重要;这也是不好的。int* p = new int(); save(p); delete p; - CB Bailey
@CharlesBailey:有很多事情是不好的;OP正在询问一个特定的问题,编译器似乎已经有能力识别它(用于警告返回本地指针的逻辑)。 - Scott Hunter
@ScottHunter:我的观点是存储本地对象的指针不一定是坏事。将其标记为错误会产生误报。 - CB Bailey
显示剩余2条评论
2个回答

2

有至少一种使用调试堆的调试构建方式(默认):

//d:\Program Files\Microsoft Visual Studio ?\VC\crt\src\dbgint.h
\#define nNoMansLandSize 4
typedef struct _CrtMemBlockHeader
{
    struct _CrtMemBlockHeader * pBlockHeaderNext;
    struct _CrtMemBlockHeader * pBlockHeaderPrev;
    char *                      szFileName;
    int                         nLine;
    size_t                      nDataSize;
    int                         nBlockUse;
    long                        lRequest;
    unsigned char               gap[nNoMansLandSize];
    /* followed by:
     *  unsigned char           data[nDataSize];
     *  unsigned char           anotherGap[nNoMansLandSize];
     */
} _CrtMemBlockHeader;
\#define pbData(pblock) ((unsigned char *)((_CrtMemBlockHeader *)pblock + 1))

有一个分配头,以间隙结束,因此在指针之前不大可能出现0xFDFDFDFD - 这不是完美的,但可能会有所帮助...

if (\*((int\*)pointer-1) == 0xFDFDFD) { // stack pointer }

0

不,没有可靠且可移植的方法可以区分指向本地变量和指向堆对象的指针。也没有声明性的方法可以防止这种情况发生。

有一些依赖于特定系统内存布局的黑科技可以在运行时通过调用未指定的行为来实现(请参见this answer中的示例),但如果您决定尝试它们,那么就要自己承担风险。


但是,如果编译器能够识别函数尝试返回本地指针的情况,并且如果有像OP建议的属性,为什么编译器不能使用相同的逻辑生成警告呢? - Scott Hunter
@ScottHunter 因为编译器无法通过静态分析代码来可靠地确定它。将指针存储在全局变量中只是绕过检查的一种方式 - 您可以将其存储在结构成员中,转换为字节数组等。添加不可靠的检查将会失去意义。 - Sergey Kalinichenko
这与已实现的返回检查有何不同? - Scott Hunter
1
@Scott。因为编译器知道在“return”之后返回的指针将不再有效。在其他情况下,它无法可靠地确定指针是否会在函数结束后使用。结果要么是无用的警告(很快就会被忽略),要么是错过的情况(这将违背目的)。为了避免踩到自己的脚,瞄准正确比指向下时枪支失效要好得多。 - Remo.D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接