This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Fix ftw and nftw


Hi!

If the depth level at which {,n}ftw callback decides to return non-zero is
bigger than the descriptors argument passed to {,n}ftw, we trigger an
assertion in ftw_dir and depending on NDEBUG either don't behave correctly
or abort. It is perfectly valid situation though, we just need to free dir
contents and return that value.
This patch fixes this plus adds a testcase for this (which fails unless this
patch is applied).

2000-12-14  Jakub Jelinek  <jakub@redhat.com>

	* io/ftw.c (ftw_dir): If process_entry returned non-zero result
	and dir.stream is NULL, only free dir.content.
	* io/ftwtest.c (cb, main): Add --early-exit option to test it.
	* io/ftwtest-sh: Test with --early-exit.

--- libc/io/ftw.c.jj	Wed May  3 10:19:51 2000
+++ libc/io/ftw.c	Thu Dec 14 13:21:16 2000
@@ -426,18 +426,17 @@ ftw_dir (struct ftw_data *data, struct S
       int save_err;
       char *runp = dir.content;
 
-      assert (result == 0);
+      if (result == 0)
+	while (*runp != '\0')
+	  {
+	    char *endp = strchr (runp, '\0');
 
-      while (*runp != '\0')
-	{
-	  char *endp = strchr (runp, '\0');
+	    result = process_entry (data, &dir, runp, endp - runp);
+	    if (result != 0)
+	      break;
 
-	  result = process_entry (data, &dir, runp, endp - runp);
-	  if (result != 0)
-	    break;
-
-	  runp = endp + 1;
-	}
+	    runp = endp + 1;
+	  }
 
       save_err = errno;
       free (dir.content);
--- libc/io/ftwtest.c.jj	Fri Sep 19 18:57:36 1997
+++ libc/io/ftwtest.c	Thu Dec 14 13:56:26 2000
@@ -10,12 +10,14 @@
 int do_depth;
 int do_chdir;
 int do_phys;
+int do_exit;
 
 struct option options[] =
 {
   { "depth", no_argument, &do_depth, 1 },
   { "chdir", no_argument, &do_chdir, 1 },
   { "phys", no_argument, &do_phys, 1 },
+  { "early-exit", no_argument, &do_exit, 1 },
   { NULL, 0, NULL, 0 }
 };
 
@@ -34,6 +36,9 @@ const char *flag2name[] =
 int
 cb (const char *name, const struct stat *st, int flag, struct FTW *f)
 {
+  if (do_exit && strcmp (name + f->base, "file@2"))
+    return 0;
+
   printf ("base = \"%.*s\", file = \"%s\", flag = %s",
 	  f->base, name, name + f->base, flag2name[flag]);
   if (do_chdir)
@@ -43,7 +48,7 @@ cb (const char *name, const struct stat 
       free (cwd);
     }
   printf (", level = %d\n", f->level);
-  return 0;
+  return do_exit ? 26 : 0;
 }
 
 int
@@ -64,8 +69,13 @@ main (int argc, char *argv[])
   if (do_phys)
     flag |= FTW_PHYS;
 
-  r = nftw (optind < argc ? argv[optind] : ".", cb, 3, flag);
-  if (r)
+  r = nftw (optind < argc ? argv[optind] : ".", cb, do_exit ? 1 : 3, flag);
+  if (r < 0)
     perror ("nftw");
+  if (do_exit)
+    {
+      puts (r == 26 ? "succeeded" : "failed");
+      return r == 26 ? 0 : 1;
+    }
   return r;
 }
--- libc/io/ftwtest-sh.jj	Thu Jul 27 15:58:52 2000
+++ libc/io/ftwtest-sh	Thu Dec 14 13:58:47 2000
@@ -5,10 +5,12 @@ objpfx=$1
 
 # We expect one parameter which is the test program.  This must understand
 # a number options:
-#   --phys	use the FTW_PHYS flag
-#   --chdir	use the FTW_CHDIR and print the current directory in the
-#		callback
-#   --depth	use the FTW_DEPTH flag
+#   --phys		use the FTW_PHYS flag
+#   --chdir		use the FTW_CHDIR and print the current directory
+#			in the callback
+#   --depth		use the FTW_DEPTH flag
+#   --early-exit 	print file@2 item only and return non-zero from the
+#			callback when it is seen
 testprogram=$2
 
 # We cannot test this as root.
@@ -133,6 +135,15 @@ base = "$tmp/ftwtest.d/foo/lvl1/", file 
 base = "$tmp/ftwtest.d/foo/lvl1/lvl2/", file = "file@2", flag = FTW_F, cwd = $tmpreal/ftwtest.d/foo/lvl1/lvl2, level = 4
 base = "$tmp/ftwtest.d/foo/lvl1/lvl2/", file = "lvl3", flag = FTW_D, cwd = $tmpreal/ftwtest.d/foo/lvl1/lvl2, level = 4
 base = "$tmp/ftwtest.d/foo/lvl1/lvl2/lvl3/", file = "file@3", flag = FTW_F, cwd = $tmpreal/ftwtest.d/foo/lvl1/lvl2/lvl3, level = 5
+EOF
+rm $testout
+
+LD_LIBRARY_PATH=$objpfx $ldso $testprogram --early-exit $tmpdir |
+    sort > $testout
+
+cat <<EOF | cmp $testout - || exit 1
+base = "$tmp/ftwtest.d/foo/lvl1/lvl2/", file = "file@2", flag = FTW_F, level = 4
+succeeded
 EOF
 rm $testout
 

	Jakub

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]