On Sun, Aug 16, 2020 at 1:54 AM Jeff King <peff@xxxxxxxx> wrote: > > On Sun, Aug 16, 2020 at 06:59:10AM +0000, Elijah Newren via GitGitGadget wrote: > > > From: Elijah Newren <newren@xxxxxxxxx> > > > > The calling convention for the dir API is supposed to end with a call to > > clear_directory() to free up no longer needed memory. However, > > clear_directory() didn't free dir->entries or dir->ignored. I believe > > this was oversight, but a number of callers noticed memory leaks and > > started free'ing these, but often somewhat haphazardly (sometimes > > freeing the entries in the arrays, and sometimes only free'ing the > > arrays themselves). This suggests the callers weren't trying to make > > sure any possible memory used might be free'd, but just the memory they > > noticed their usecase definitely had allocated. This also caused the > > extra memory deallocations to be duplicated in many places. > > > > Fix this mess by moving all the duplicated free'ing logic into > > clear_directory(). > > Makes sense. I don't know the dir.c code very well, so my worry would be > that some caller really wanted the other fields left untouched. But > looking over the callers, it seems they're all clearing it before the > struct goes out of scope. It's possible that they could have created > other pointer references, but it seems unlikely (and I'd argue they > should stop doing that and make their own copies of the data). E.g., > wt_status_collect_untracked() sticks names into a string_list, but it > sets strdup_strings to make its own copy, so it's good. > > > @@ -3034,6 +3031,13 @@ void clear_directory(struct dir_struct *dir) > > free(group->pl); > > } > > > > + for (i = 0; i < dir->ignored_nr; i++) > > + free(dir->ignored[i]); > > + for (i = 0; i < dir->nr; i++) > > + free(dir->entries[i]); > > + free(dir->ignored); > > + free(dir->entries); > > + > > stk = dir->exclude_stack; > > while (stk) { > > struct exclude_stack *prev = stk->prev; > > In most of our "clear" functions, the struct is ready for use again > (i.e., fields are set back to the initialized state). I don't think any > caller cares at this point, but it may be worth doing while we are here > as a least-surprise thing. That would mean setting these pointers to > NULL, and probably a few others that you aren't touching here. > > Perhaps even easier would be to add a dir_init() call at the end after > your next patch adds that function. Make sense; I'll fix it up.