Subject: diff fails on any but small directories (+FIX) Index: bin/diff/diffdir.c 2.11BSD Description: Doing a "diff directorya directoryb" when either directory is not very small fails with and "out of memory" error. Repeat-By: Have two directories comparable in size to /usr/src/sys/sys (or the Fortran runtime directories /usr/src/usr.lib/libU77, libI77, libF77). Attempt to "diff" the two directories. Fix: The problem is once again "realloc()". The loop in setupdir() (diffdir.c) which scans the directory to build up the list of filenames to be sorted does a realloc() after each and every file name! After each realloc() a malloc() is performed to allocate space for the file name - this fragments the memory such that the next realloc() must expand the process space. It doesn't take many files in a directory to cause 'diff' to run out of memory even though sufficient memory exists to hold the entire directory (and the filenames in memory) if only realloc() weren't used. The fix is to quickly prescan the directory and count the number of files. This is not as slow or bad as it would first appear: if the directory is small then the scan will be fast, if the directory is large then the scan time doesn't matter because 'diff' will at least handle the directory rather than failing with the "out of memory" error. The inode type 'ino_t' was substituted for 'u_long', this saves two bytes per file from having to be malloc'd for each file in a directory. Also the (silly) sccsid[] stuff was ifdef'd out along the way. ------------------------------------------------------------------------- *** /usr/src/bin/diff/diff.c.old Thu Apr 3 11:15:34 1986 --- /usr/src/bin/diff/diff.c Mon Nov 11 16:24:25 1991 *************** *** 1,4 **** --- 1,6 ---- + #if !defined(lint) && defined(DOSCCS) static char sccsid[] = "@(#)diff.c 4.6 4/3/86"; + #endif #include "diff.h" /* *** /usr/src/bin/diff/diffdir.c.old Tue Aug 28 19:38:23 1984 --- /usr/src/bin/diff/diffdir.c Tue Nov 12 15:16:59 1991 *************** *** 1,4 **** --- 1,6 ---- + #if !defined(lint) && defined(DOSCCS) static char *sccsid = "@(#)diffdir.c 4.9 (Berkeley) 8/28/84"; + #endif #include "diff.h" /* *************** *** 12,18 **** #define DIRECT 8 /* Directory */ struct dir { ! u_long d_ino; short d_reclen; short d_namlen; char *d_entry; --- 14,20 ---- #define DIRECT 8 /* Directory */ struct dir { ! ino_t d_ino; short d_reclen; short d_namlen; char *d_entry; *************** *** 181,187 **** --- 183,197 ---- done(); } nitems = 0; + #ifdef pdp11 + while (readdir(dirp)) + nitems++; + rewinddir(dirp); + dp = (struct dir *)calloc(nitems+1, sizeof (struct dir)); + nitems = 0; + #else dp = (struct dir *)malloc(sizeof (struct dir)); + #endif if (dp == 0) { fprintf(stderr, "diff: ran out of memory\n"); done(); *************** *** 200,205 **** --- 210,216 ---- } strcpy(ep->d_entry, rp->d_name); } + #ifndef pdp11 dp = (struct dir *)realloc((char *)dp, (nitems + 1) * sizeof (struct dir)); if (dp == 0) { *************** *** 206,211 **** --- 217,223 ---- fprintf(stderr, "diff: ran out of memory\n"); done(); } + #endif } dp[nitems].d_entry = 0; /* delimiter */ closedir(dirp); *** /usr/src/bin/diff/diffh.c.old Sat Jan 11 14:43:14 1986 --- /usr/src/bin/diff/diffh.c Mon Nov 11 16:25:13 1991 *************** *** 1,4 **** --- 1,6 ---- + #if !defined(lint) && defined(DOSCCS) static char sccsid[] = "@(#)diffh.c 4.4 11/27/85"; + #endif #include #include *** /usr/src/bin/diff/diffreg.c.old Thu Feb 12 02:09:58 1987 --- /usr/src/bin/diff/diffreg.c Mon Nov 11 16:25:35 1991 *************** *** 1,4 **** --- 1,6 ---- + #if !defined(lint) && defined(DOSCCS) static char sccsid[] = "@(#)diffreg.c 4.16 3/29/86"; + #endif #include "diff.h" /*