When getcwd() fails, the stat buffer 'swd' is used uninitialized
by the else clause.  Since it is used in both clauses we should
perform the stat before the if().

However, fixing this causes 'cp' to be unitialized in some case so
initialize cp to NULL and move the "cp == NULL" check out of the
first if() clause now that it can be true in either case.

Found by clang analyzer.

 - todd

Index: bin/csh/dir.c
===================================================================
RCS file: /cvs/src/bin/csh/dir.c,v
retrieving revision 1.21
diff -u -p -u -r1.21 dir.c
--- bin/csh/dir.c       26 Dec 2015 13:48:38 -0000      1.21
+++ bin/csh/dir.c       19 Sep 2018 15:14:43 -0000
@@ -64,7 +64,7 @@ void
 dinit(Char *hp)
 {
     char *tcp;
-    Char *cp;
+    Char *cp = NULL;
     struct directory *dp;
     char    path[PATH_MAX];
     static const char emsg[] = "csh: Trying to start from \"%s\"\n";
@@ -75,45 +75,45 @@ dinit(Char *hp)
        (void) fprintf(csherr, "csh: %s\n", strerror(errno));
        if (hp && *hp) {
            tcp = short2str(hp);
-           if (chdir(tcp) == -1)
-               cp = NULL;
-           else
+           if (chdir(tcp) == 0)
                cp = hp;
            (void) fprintf(csherr, emsg, vis_str(hp));
        }
-       else
-           cp = NULL;
-       if (cp == NULL) {
-           (void) fprintf(csherr, emsg, "/");
-           if (chdir("/") == -1)
-               /* I am not even try to print an error message! */
-               xexit(1);
-           cp = SAVE("/");
-       }
     }
     else {
        struct stat swd, shp;
 
-       /*
-        * See if $HOME is the working directory we got and use that
-        */
-       if (hp && *hp &&
-           stat(tcp, &swd) != -1 && stat(short2str(hp), &shp) != -1 &&
-           swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino)
-           cp = hp;
-       else {
-           char   *cwd;
-
+       if (stat(tcp, &swd) == -1) {
+           (void) fprintf(csherr, "csh: %s: %s\n", tcp, strerror(errno));
+       } else {
            /*
-            * use PWD if we have it (for subshells)
+            * See if $HOME is the working directory we got and use that
             */
-           if ((cwd = getenv("PWD")) != NULL) {
-               if (stat(cwd, &shp) != -1 && swd.st_dev == shp.st_dev &&
-                   swd.st_ino == shp.st_ino)
-                   tcp = cwd;
+           if (hp && *hp && stat(short2str(hp), &shp) != -1 &&
+               swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino)
+               cp = hp;
+           else {
+               char   *cwd;
+
+               /*
+                * use PWD if we have it (for subshells)
+                */
+               if ((cwd = getenv("PWD")) != NULL) {
+                   if (stat(cwd, &shp) != -1 && swd.st_dev == shp.st_dev &&
+                       swd.st_ino == shp.st_ino)
+                       tcp = cwd;
+               }
+               cp = dcanon(SAVE(tcp), STRNULL);
            }
-           cp = dcanon(SAVE(tcp), STRNULL);
        }
+    }
+
+    if (cp == NULL) {
+       (void) fprintf(csherr, emsg, "/");
+       if (chdir("/") == -1)
+           /* I am not even try to print an error message! */
+           xexit(1);
+       cp = SAVE("/");
     }
 
     dp = xcalloc(1, sizeof(struct directory));

Reply via email to