[prev in list] [next in list] [prev in thread] [next in thread] 

List:       coreutils-bug
Subject:    coreutils-5.0: bugs in readlink --canonicalize
From:       Jim Meyering <jim () meyering ! net>
Date:       2003-04-10 17:22:45
Message-ID: 85n0iygtcq.fsf () pi ! meyering ! net
[Download RAW message or body]

`readlink --canonicalize' (aka lib/canonicalize.c) had problems
on e.g., Solaris systems.  This affects only systems that lack
canonicalize_file_name and that have the resolvepath function,
like Solaris.  Here are examples of how it fails:

  $ readlink --canonical .
  [Exit 1]
  $ readlink --canonical /no-such-file
  readlink: memory exhausted
  [Exit 1]
  $ readlink --canonical /
  /cÈ

Note that in the last example above, there are two extra bytes
after the `/'.

Although df.c also uses canonicalize_file_name, it's not affected.

Here's the fix:

	* canonicalize.c (canonicalize_file_name) [HAVE_RESOLVEPATH]: Remove
	stray semicolon that caused `readlink --canonical RELATIVE_NAME' to
	fail on e.g., Solaris systems.  Reported by Bruce Korb.
	(canonicalize_file_name): Return NULL immediately if resolvepath fails.
	Otherwise, `readlink --canonical /no-such-file' would exhaust
	virtual memory on some systems (e.g. Solaris).
	(canonicalize_file_name): Always free `extra_buf' before returning.
	(canonicalize_file_name): NUL-terminate the result.

Yes, I'll be adding a few tests, soon :-)

Index: lib/canonicalize.c
===================================================================
RCS file: /fetish/cu/lib/canonicalize.c,v
retrieving revision 1.3
retrieving revision 1.7
diff -u -p -u -p -r1.3 -r1.7
--- lib/canonicalize.c	20 Jan 2003 16:41:19 -0000	1.3
+++ lib/canonicalize.c	10 Apr 2003 17:03:26 -0000	1.7
@@ -130,7 +130,7 @@ canonicalize_file_name (const char *name
     {
       char *wd;
 
-      if (!(wd = xgetcwd ()));
+      if (!(wd = xgetcwd ()))
 	return NULL;
 
       extra_buf = path_concat (wd, name, NULL);
@@ -147,18 +147,22 @@ canonicalize_file_name (const char *name
       resolved_size = 2 * resolved_size + 1;
       resolved = xmalloc (resolved_size);
       resolved_len = resolvepath (name, resolved, resolved_size);
+      if (resolved_len < 0)
+	{
+	  free (resolved);
+	  free (extra_buf);
+	  return NULL;
+	}
       if (resolved_len < resolved_size)
 	break;
       free (resolved);
     }
 
-  if (resolved_len < 0)
-    {
-      free (resolved);
-      resolved = NULL;
-    }
-
   free (extra_buf);
+
+  /* NUL-terminate the resulting name.  */
+  resolved[resolved_len] = '\0';
+
   return resolved;
 
 #else /* !HAVE_RESOLVEPATH */



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic