Brad Hubbard - 2011-12-14

MCPP fails to resolve symbolic links properly and segfaults as a result.

Steps to Reproduce:
mkdir -p /tmp/a/g /tmp/a/h /tmp/e
cd /tmp/a/g
ln -sf ../h /tmp/a/g/c
ln -sf /tmp/a/g /tmp/e/f
ln -sf /tmp/e/f /tmp/a/b
echo "- this is version VERSION of this file -" >/tmp/a/b/c/d.cpp
mcpp -DVERSION=1.2.3 /tmp/a/b/c/d.cpp

Can't open input file "/tmp/e/h/d.cpp".
./repro: line 9: 22620 Segmentation fault      (core dumped) mcpp
-DVERSION=1.2.3 /tmp/a/b/c/d.cpp

Below is a possible patch which uses realpath() instead of readlink() and removes the deref_syml() function.

-- a/src/main.c 2011-11-26 04:32:05.377872854 +1000
+++ a/src/main.c 2011-12-01 05:23:00.158478861 +1000
@@ -437,11 +437,11 @@
     clear_symtable();
#endif

-    if (fp_in != stdin)
+    if (fp_in && (fp_in != stdin))
         fclose( fp_in);
-    if (fp_out != stdout)
+    if (fp_out && (fp_out != stdout))
         fclose( fp_out);
-    if (fp_err != stderr)
+    if (fp_err && (fp_err != stderr))
         fclose( fp_err);

     if (mcpp_debug & MEMORY)
-- a/src/system.c 2011-12-01 06:39:27.118437985 +1000
+++ a/src/system.c 2011-12-01 06:46:55.763451557 +1000
@@ -145,10 +145,6 @@
                 /* Normalize include directory path */
static char *   norm_path( const char * dir, const char * fname, int inf
         , int hmap);    /* Normalize pathname to compare    */
-#if SYS_FAMILY == SYS_UNIX
-static void     deref_syml( char * slbuf1, char * slbuf2, char * chk_start);
-                /* Dereference symbolic linked directory and file   */
-#endif
#if COMPILER == GNUC
static void     init_gcc_macro( void);
                 /* Predefine GCC-specific macros    */
@@ -2491,40 +2487,21 @@
             return  NULL;
     }
#endif
-    if (! fname) {
-        slbuf1 = PATH_DELIM;          /* Append PATH_DELIM    */
-        slbuf1 = EOS;
-    }
#if SYS_FAMILY == SYS_UNIX
     /* Dereference symbolic linked directory or file, if any    */
-    slbuf1 = EOS;     /* Truncate PATH_DELIM and 'fname' part, if any */
     slbuf2 = EOS;
-    if (*dir && ! fname) {      /* Registering include directory    */
-        /* Symbolic link check of directories are required  */
-        deref_syml( slbuf1, slbuf2, slbuf1);
-    } else if (fname) {                             /* Regular file */
-        len = strlen( slbuf1);
-        strcat( slbuf1, fname);
-        deref_syml( slbuf1, slbuf2, slbuf1 + len);
-                                /* Symbolic link check of directory */
-        if ((len = readlink( slbuf1, slbuf2, PATHMAX)) > 0) {
-            /* Dereference symbolic linked file (not directory) */
-            *(slbuf2 + len) = EOS;
-            cp1 = slbuf1;
-            if (slbuf2 != PATH_DELIM) {     /* Relative path    */
-                cp2 = strrchr( slbuf1, PATH_DELIM);
-                if (cp2)        /* Append to the source directory   */
-                    cp1 = cp2 + 1;
-            }
-            strcpy( cp1, slbuf2);
+    if((realpath(slbuf1, slbuf2) != NULL) && strcmp(slbuf1,slbuf2)) {
+        if (inf) {
+                mcpp_fprintf( DBG, "Dereferenced \"%s\" to \"%s\"\n"
+                        , slbuf1, slbuf2);
         }
-    }
-    if (inf) {
-        if (slbuf2)
-            mcpp_fprintf( DBG, "Dereferenced \"%s%s\" to \"%s\"\n"
-                    , dir, fname ? fname : null, slbuf1);
+        strcpy(slbuf1,slbuf2);
     }
#endif
+    if (! fname) {
+        slbuf1 = PATH_DELIM;          /* Append PATH_DELIM    */
+        slbuf1 = EOS;
+    }
     len = strlen( slbuf1);
     start = norm_name = xmalloc( len + 1);  /* Need a new buffer    */
     strcpy( norm_name, slbuf1);
@@ -2668,43 +2645,6 @@
     return  norm_name;
}

-#if SYS_FAMILY == SYS_UNIX

-static void     deref_syml(
-    char *      slbuf1,                     /* Original path-list   */
-    char *      slbuf2,                     /* Working buffer       */
-    char *      chk_start                   /* Pointer into slbuf1  */
-)
-/* Dereference symbolic linked directory    */
-{
-    char *      cp2;
-    int         len;                /* Should be int, not size_t    */
-
-    while ((chk_start = strchr( chk_start, PATH_DELIM)) != NULL) {
-        *chk_start = EOS;
-        if ((len = readlink( slbuf1, slbuf2, PATHMAX)) > 0) {
-            /* Dereference symbolic linked directory    */
-            cp2 = strrchr( slbuf1, PATH_DELIM); /* Previous delimiter       */
-            *chk_start = PATH_DELIM;
-            strcpy( slbuf2 + len, chk_start);
-            if (slbuf2 == PATH_DELIM) {     /* Absolute path    */
-                strcpy( slbuf1, slbuf2);
-                chk_start = slbuf1 + len + 1;
-            } else {
-                if (cp2)
-                    chk_start = cp2 + 1;
-                else
-                    chk_start = slbuf1;
-                strcpy( chk_start, slbuf2);     /* Rewrite the path */
-                chk_start += len;
-            }
-        } else {
-            *chk_start++ = PATH_DELIM;
-        }
-    }
-}
-#endif
-
#if COMPILER == GNUC

static void init_gcc_macro( void)