gpt4 book ai didi

c - 从函数 readdir 释放(删除)分配的内存

转载 作者:IT王子 更新时间:2023-10-29 01:03:26 26 4
gpt4 key购买 nike

我是在Linux环境下使用C编程语言来读取一个目录下的文件。我有包括 #include<dirent.h>在我的代码中,我正在使用函数 readdir() .

根据 Linux 在线页面,它说不要调用 free()在指向 dirent 的结果指针上结构,因为它可能分配在堆栈上。

你能帮我理解它是如何工作的吗?我不明白为什么我们不必删除 struct dirent .什么时候删的,谁删的?

Here是我正在谈论的摘录:

On success, readdir() returns a pointer to a dirent structure. (This structure may be statically allocated; do not attempt to free(3) it.) If the end of the directory stream is reached, NULL is returned and errno is not changed. If an error occurs, NULL is returned and errno is set appropriately.

最佳答案

man readdir 字面意思是:

On success, readdir() returns a pointer to a dirent structure. (This structure may be statically allocated; do not attempt to free(3) it.)

(添加了代码格式化程序。)

这意味着它的空间不是在运行时分配的,例如堆栈或空闲存储内存,而是静态:它在可执行文件本身中,与字符串文字相比,区别在于写入字符串文字是未定义的行为。

想象一下实现是这样的:

struct dirent *readdir(DIR *dirp) {
static struct dirent dir;

/* Fill dir with appropriate values. */

return &dir;
}

dir 在这里静态分配。返回它的地址并没有错,因为它在程序的整个运行期间都存在。

这是我的 glibc 2.22 实现中 readdir 的实际源代码(路径是 /sysdeps/posix/readdir.c):

DIRENT_TYPE *
__READDIR (DIR *dirp)
{
DIRENT_TYPE *dp;
int saved_errno = errno;

#if IS_IN (libc)
__libc_lock_lock (dirp->lock);
#endif

do
{
size_t reclen;

if (dirp->offset >= dirp->size)
{
/* We've emptied out our buffer. Refill it. */

size_t maxread;
ssize_t bytes;

#ifndef _DIRENT_HAVE_D_RECLEN
/* Fixed-size struct; must read one at a time (see below). */
maxread = sizeof *dp;
#else
maxread = dirp->allocation;
#endif

bytes = __GETDENTS (dirp->fd, dirp->data, maxread);
if (bytes <= 0)
{
/* On some systems getdents fails with ENOENT when the
open directory has been rmdir'd already. POSIX.1
requires that we treat this condition like normal EOF. */
if (bytes < 0 && errno == ENOENT)
bytes = 0;

/* Don't modifiy errno when reaching EOF. */
if (bytes == 0)
__set_errno (saved_errno);
dp = NULL;
break;
}
dirp->size = (size_t) bytes;

/* Reset the offset into the buffer. */
dirp->offset = 0;
}

dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];

#ifdef _DIRENT_HAVE_D_RECLEN
reclen = dp->d_reclen;
#else
/* The only version of `struct dirent*' that lacks `d_reclen'
is fixed-size. */
assert (sizeof dp->d_name > 1);
reclen = sizeof *dp;
/* The name is not terminated if it is the largest possible size.
Clobber the following byte to ensure proper null termination. We
read jst one entry at a time above so we know that byte will not
be used later. */
dp->d_name[sizeof dp->d_name] = '\0';
#endif

dirp->offset += reclen;

#ifdef _DIRENT_HAVE_D_OFF
dirp->filepos = dp->d_off;
#else
dirp->filepos += reclen;
#endif

/* Skip deleted files. */
} while (dp->d_ino == 0);

#if IS_IN (libc)
__libc_lock_unlock (dirp->lock);
#endif

return dp;
}

我对glibc了解不多,但是行

dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];

对我们来说似乎是最有趣的。据我所知,dirp->data 是这里的static 数据。


这就是为什么有可重入替代方案 readdir_rreaddir不可重入的原因。 想象一下两个线程同时执行 readdir。两者都将尝试填充 dir,它在所有 readdir 调用之间共享,同时导致无序的内存读取/写入。

关于c - 从函数 readdir 释放(删除)分配的内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34550766/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com