On 10/12/2015 02:00 PM, Jonathan Leffler wrote:
1. Has anyone else seen anything similar on El Capitan?
2. Does anyone have an idea how to get rid of the trashed directories?
3. How can we modify the test so it doesn't fail catastrophically like this on El Capitan? 4. Do I need to report a bug to Apple separately from this report to GNU Tar?

For (4), OS X is clearly busted here. A user-mode application shouldn't be able to create a directory that 'rm -fr' can't remove. Please feel free to report the bug to Apple. The problem will occur with many GNU tools' installation procedure, as they're all using Gnulib and Gnulib tries to check for getcwd bugs like this one.

For (2) I suggest using coreutils; 'rm -fr directory should do the trick if you're using GNU rm.

For (3) we need to figure out why the test doesn't clean up after itself on El Capitan. It's supposed to. Please compile and run the attached test program in a place where you don't mind having long directory chains. On my GNU/Linux host, I can do something like this:

  gcc t.c
  strace ./a.out

and the 'strace' output contains the following, showing that the test program cleans up after itself. Please find out why it's not doing so under El Capitan. OS X lacks strace, but you can use a debugger or dtruss or whatever your favorite tool is. Thanks.

mkdir("confdir-14B---", 0700)           = 0
chdir("confdir-14B---")                 = 0
mkdir("confdir-14B---", 0700)           = 0
chdir("confdir-14B---")                 = 0
...
mkdir("confdir-14B---", 0700)           = 0
chdir("confdir-14B---")                 = 0
getcwd(0x1736010, 4096) = -1 ENAMETOOLONG (File name too long) [a whole bunch of other stuff, which eventually succeeds. Now comes cleanup time....] rmdir("confdir-14B---") = -1 ENOENT (No such file or directory)
chdir("..")                             = 0
rmdir("confdir-14B---")                 = 0
chdir("..")                             = 0
...
chdir("..")                             = 0
rmdir("confdir-14B---")                 = 0
exit_group(0)                           = ?

#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>


/* Arrange to define PATH_MAX, like "pathmax.h" does. */
#include <unistd.h>
#include <limits.h>
#include <sys/param.h>

#if !defined PATH_MAX && defined MAXPATHLEN
# define PATH_MAX MAXPATHLEN
#endif

#ifndef S_IRWXU
# define S_IRWXU 0700
#endif

/* This size is chosen to be larger than PATH_MAX (4k), yet smaller than
   the 16kB pagesize on ia64 linux.  Those conditions make the code below
   trigger a bug in glibc's getcwd implementation before 2.4.90-10.  */
#define TARGET_LEN (5 * 1024)

int
main (void)
{
  char *cwd;
  size_t initial_cwd_len;
  int fail = 0;

  cwd = getcwd (NULL, 0);
  if (cwd == NULL)
    return 2;

  initial_cwd_len = strlen (cwd);
  free (cwd);

  if (1)
    {
      static char const dir_name[] = "confdir-14B---";
      size_t desired_depth = ((TARGET_LEN - 1 - initial_cwd_len)
                              / sizeof dir_name);
      size_t d;
      for (d = 0; d < desired_depth; d++)
        {
          if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0)
            {
              if (! (errno == ERANGE || errno == ENAMETOOLONG
                     || errno == ENOENT))
                fail = 3; /* Unable to construct deep hierarchy.  */
              break;
            }
        }

      /* If libc has the bug in question, this invocation of getcwd
         results in a failed assertion.  */
      cwd = getcwd (NULL, 0);
      if (cwd == NULL)
        fail = 4; /* getcwd didn't assert, but it failed for a long name
                     where the answer could have been learned.  */
      free (cwd);

      /* Call rmdir first, in case the above chdir failed.  */
      rmdir (dir_name);
      while (0 < d--)
        {
          if (chdir ("..") < 0)
            {
              fail = 5;
              break;
            }
          rmdir (dir_name);
        }
    }

  return fail;
}

Reply via email to