当前位置:  开发笔记 > 运维 > 正文

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

如何解决《从函数readdir释放(删除)已分配的内存》经验,为你挑选了1个好方法。

我在Linux环境中使用C编程语言来读取目录中的文件.我已经包含#include在我的代码中并使用了该函数readdir().

根据Linux在线页面,它说不会调用free()结果指针到dirent结构,因为它可能被分配在堆栈上.

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

以下是我所说的摘录:

成功时,readdir()返回指向dirent结构的指针.(此结构可以静态分配;不要尝试free(3)它.)如果到达目录流的末尾,NULL则返回并且errno不会更改.如果发生错误,NULL则返回并errno适当设置.

cadaniluk.. 10

man readdir 字面上说:

成功时, readdir()返回指向dirent结构的指针.(此结构可以静态分配;不要尝试 free(3).)

(代码格式化程序已添加.)

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

想象一下实现是这样的:

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

    /* Fill dir with appropriate values. */

    return &dir;
}

dir在这里静态分配.返回它的地址没有错,因为它存在于程序的整个运行时间中.

这是readdir我的glibc 2.22实现的实际源代码(路径是/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->datastatic数据.


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



1> cadaniluk..:

man readdir 字面上说:

成功时, readdir()返回指向dirent结构的指针.(此结构可以静态分配;不要尝试 free(3).)

(代码格式化程序已添加.)

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

想象一下实现是这样的:

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

    /* Fill dir with appropriate values. */

    return &dir;
}

dir在这里静态分配.返回它的地址没有错,因为它存在于程序的整个运行时间中.

这是readdir我的glibc 2.22实现的实际源代码(路径是/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->datastatic数据.


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

推荐阅读
ifx0448363
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有