已经释放内存

发布于 2024-11-26 20:20:44 字数 118 浏览 4 评论 0 原文

C 中是否有任何方法可以知道内存块之前是否已被 free() 释放?我可以做一些像...

if(isFree(pointer))
{ 
    //code here
}

Is there any way in C to know if a memory block has previously been freed with free()? Can i do something like...

if(isFree(pointer))
{ 
    //code here
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

夜未央樱花落 2024-12-03 20:20:44

好吧,如果您需要检查指针是否已被释放,您可能需要检查您的设计。您永远不必跟踪指针的引用计数或指针是否被释放。另外,有些指针不是动态分配的内存,所以我希望您指的是用 malloc() 调用的指针。这是我的观点,但如果你有一个可靠的设计,你应该知道你的指针指向的东西何时被使用。

我看到这个不起作用的唯一地方是在整体内核中,因为内存中的页面由于共享映射等原因需要使用计数。

在您的情况下,只需将未使用的指针设置为 NULL 并检查即可。这为您提供了一种有保证的方式来了解已分配的结构中是否有未使用的字段。一个简单的规则是,无论何时释放需要以上述方式检查的指针,只需将其设置为 NULL 并将 isFree() 替换为 if point == NULL。这样就不需要跟踪引用计数,并且您可以确定指针是否有效并且没有指向垃圾。

Ok if you need to check whether a pointer has already been freed you may want to check your design. You should never have to either track reference count on a pointer or if it's freed. Also some pointers are not dynamically allocated memory so I hope you mean ones called with malloc(). This is my opinion but again if you have a solid design you should know when the things your pointers point to are done being used.

The only place I have seen this not work is in monolithic kernels because pages in memory need a usage count because of shared mappings among other things.

In your case simply set unused pointers to NULL and check that. This gives you a guaranteed way of knowing in the case that you have unused fields in structures that were malloced. A simple rule is wherever you free a pointer that needs to be checked in the above way just set it to NULL and replace isFree() with if pointer == NULL. This way no reference count needs to be tracked and you know for sure if your pointer is valid and not pointing to garbage.

没企图 2024-12-03 20:20:44

不,没有办法。

但是,您可以使用一些代码规则,如下所示:

始终始终始终使用 malloc 保护分配:

void * vp;
if((vp = malloc(SIZE))==NULL){
   /* do something dreadful here to respond to the out of mem */
   exit(-1);
}

释放指针后,将其设置为 0

free(vp); vp = (void*)0;
/* I like to put them on one line and think of them as one peration */

任何您想要的地方要使用你的“被释放”功能,只需在评论中说

if(vp == NULL)[
    /* it's been freed already */
}

更新

@Jesus即可:

我真的不能推荐这个,因为一旦你完成了这个
内存指针应该立即超出范围(或者至少在
释放它的函数的末尾)这些悬空指针
存在就是不适合我。

如果可能的话,这通常是一个很好的做法;问题是在现实生活中用 C 语言通常是不可能的。以包含双向链接行列表的文本编辑器为例。该列表非常简单:

struct line {
    struct line * prev;
    struct line * next;
    char * contents;
}

我定义一个 guarded_malloc 函数,该函数分配内存

void * guarded_malloc(size_t sz){
    return (malloc(sz)) ? : exit(-1); /* cute, eh? */
}

并使用 newLine() 创建列表节点,

struct line * newLine(){
    struct line * lp;
    lp = (struct line *) guarded_malloc(sizeof(struct line));
    lp->prev = lp->next = lp-contents = NULL ;
    return lp;
}

我在字符串 s 中添加文本到我的行

lp->contents = guarded_malloc(strlen(s)+1);
strcpy(lp->contents,s);

,不要怀疑我应该使用有界长度的形式,这只是一个例子。

现在,如何实现删除释放后超出范围的 line 内容?

No, there is no way.

You can, however, use a little code discipline as follows:

Always always always guard allocations with malloc:

void * vp;
if((vp = malloc(SIZE))==NULL){
   /* do something dreadful here to respond to the out of mem */
   exit(-1);
}

After freeing a pointer, set it to 0

free(vp); vp = (void*)0;
/* I like to put them on one line and think of them as one peration */

Anywhere you'd be tempted to use your "is freed" function, just say

if(vp == NULL)[
    /* it's been freed already */
}

Update

@Jesus in comments says:

I can't really recommend this because as soon as you're done with that
memory the pointer should go out of scope immediately (or at least at
the end of the function that releases it) these dangling pointers
existence just doesn't sit right with me.

That's generally good practice when possible; the problem is that in real life in C it's often not possible. Consider as an example a text editor that contains a doubly-linked list of lines. The list is really simple:

struct line {
    struct line * prev;
    struct line * next;
    char * contents;
}

I define a guarded_malloc function that allocates memory

void * guarded_malloc(size_t sz){
    return (malloc(sz)) ? : exit(-1); /* cute, eh? */
}

and create list nodes with newLine()

struct line * newLine(){
    struct line * lp;
    lp = (struct line *) guarded_malloc(sizeof(struct line));
    lp->prev = lp->next = lp-contents = NULL ;
    return lp;
}

I add text in string s to my line

lp->contents = guarded_malloc(strlen(s)+1);
strcpy(lp->contents,s);

and don't quibble that I should be using the bounded-length forms, this is just an example.

Now, how can I implement deleting the contents of a line I created with the char * contents going out of scope after freeing?

雾里花 2024-12-03 20:20:44

我发现没有人能够解释为什么你想要的东西从根本上来说是不可能的。释放资源(在本例中为内存,但这同样适用于基本上任何资源)意味着将其返回到可供重用的资源池。系统可以对“地址 X 处的内存块是否已被释放?”提供合理答案的唯一方法。是为了防止该地址被重用,并为其存储一个状态标志,指示它是否已“释放”。但在本例中,它实际上并未被释放,因为它不可重用。

正如其他人所说,您试图回答这个问题的事实意味着您存在需要解决的基本设计错误。

I see nobody has addressed the reason why what you want is fundamentally impossible. To free a resource (in this case memory, but the same applies to basically any resource) means to return it to a resource pool where it's available for reuse. The only way the system could provide a reasonable answer to "Has the memory block at address X already been freed?" is to prevent this address from ever being reused, and store with it a status flag indicating whether it was "freed". But in this case, it has not actually been freed, since it is not available for reuse.

As others have said, the fact that you're trying to answer this question means you have fundamental design errors you need to address.

愚人国度 2024-12-03 20:20:44

一般来说,可移植地执行此操作的唯一方法是替换内存分配函数。但是,如果您只关心自己的代码,一种相当常见的技术是在 free() 后将指针设置为 NULL,因此任何后续使用都会抛出异常或段错误:

  free(pointer);
  pointer = NULL;

In general the only way to do this portably is to replace the memory allocation functions. But if you're only concerned about your own code, a fairly common technique is to set pointers to NULL after you free() them, so any subsequent use will throw an exception or segfault:

  free(pointer);
  pointer = NULL;
谈下烟灰 2024-12-03 20:20:44

对于特定于平台的解决方案,您可能对 Win32 函数感兴趣 IsBadReadPtr(以及其他类似的)。该函数将能够(几乎)预测从特定内存块读取时是否会出现分段错误。

注意:Microsoft 已弃用 IsBadReadPtr。

然而,这在一般情况下并不能保护你,因为操作系统对 C 运行时堆管理器一无所知,并且如果调用者传入的缓冲区没有你期望的那么大,那么堆块的其余部分从操作系统的角度来看将继续可读。

除了指向的位置之外,指针没有任何信息。你能做的最好的事情就是说“我知道这个特定的编译器版本如何分配内存,所以我将取消引用内存,将指针向后移动 4 个字节,检查大小,确保它匹配......”等等。您不能以标准方式执行此操作,因为内存分配是实现定义的。更不用说他们可能根本没有动态分配它。

顺便说一句,我建议阅读 Steve McGuire 的“编写可靠的代码”。关于内存管理的优秀章节。

For a platform-specific solution, you may be interested in the Win32 function IsBadReadPtr (and others like it). This function will be able to (almost) predict whether you will get a segmentation fault when reading from a particular chunk of memory.

Note: IsBadReadPtr has been deprecated by Microsoft.

However, this does not protect you in the general case, because the operating system knows nothing of the C runtime heap manager, and if a caller passes in a buffer that isn't as large as you expect, then the rest of the heap block will continue to be readable from an OS perspective.

Pointers have no information with them other than where they point. The best you can do is say "I know how this particular compiler version allocates memory, so I'll dereference memory, move the pointer back 4 bytes, check the size, makes sure it matches..." and so on. You cannot do it in a standard fashion, since memory allocation is implementation defined. Not to mention they might have not dynamically allocated it at all.

On a side note, I recommend reading 'Writing Solid Code' by Steve McGuire. Excellent sections on memory management.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文