ofxDirList Memory Leak again?

Hi,

Just ran into rising memory usage (only monitoring in SysInternals Process Explorer) while checking directories with ofxDirList.

I’m on Windows 7 using CodeBlocks.

It happens if you adapt the dirListExample code so that you can check the directory a number of times. In the project I’m working on I add a check in update() but if you check on a keypress you also notice the rise of a few kb every time…

I’ve tried calling DIR.reset() before calling DIR.listDir(…) but it’s still there!

I noticed there were leaks a couple of years ago but that seems to have been while the nameArray and pathArray were not vectors…

Hopefully I’m just using it wrong and someone can set me right?

e.g. If you just want to know how many images there are in a directory, so you know if something new has arrived, running this code causes a leak (when used in the dirListExample project):

  
void testApp::update(){  
    nImages = DIR.listDir("images/of_logos");  
}  

also this:

  
void testApp::update(){  
    DIR.reset();  
    nImages = DIR.listDir("images/of_logos");  
}  

Thanks!

Darren

Ok, seems like there is a malloc without a free in ofxDirlist.h

  
static DIR*  
	opendir(  
	    const char *dirname)  
	{  
	  DIR *dirp;  
	  assert (dirname != NULL);  
	  assert (strlen (dirname) < MAX_PATH);  
  
	  /* construct new DIR structure */  
	  dirp = (DIR*) malloc (sizeof (struct DIR));  
	  if (dirp != NULL) {  
	    TCHAR *p;  
  
	    /* prepare search pattern */  
	#ifdef _UNICODE  
  
	    /* convert directory name to wide character string */  
	    MultiByteToWideChar(  
	        CP_ACP,                                /* code page */  
	        0,                                     /* conversion flags */  
	        dirname,                               /* mb-string to convert */  
	        -1,                                    /* length of mb-string */  
	        dirp->patt,                            /* wc-string to produce */  
	        MAX_PATH);                             /* max length of wc-string */  
	    dirp->patt[MAX_PATH] = '\0';  
  
	    /* append search pattern to directory name */  
	    p = wcschr (dirp->patt, '\0');  
	    if (dirp->patt < p  &&  *(p-1) != '\\'  &&  *(p-1) != ':') {  
	      *p++ = '\\';  
	    }  
	    *p++ = '*';  
	    *p = '\0';  
  
	#else /* !_UNICODE */  
  
	    /* take directory name... */  
	    STRNCPY (dirp->patt, dirname, sizeof(dirp->patt));  
	    dirp->patt[MAX_PATH] = '\0';  
  
	    /* ... and append search pattern to it */  
	    p = strchr (dirp->patt, '\0');  
	    if (dirp->patt < p  &&  *(p-1) != '\\'  &&  *(p-1) != ':') {  
	      *p++ = '\\';  
	    }  
	    *p++ = '*';  
	    *p = '\0';  
  
	#endif /* !_UNICODE */  
  
	    /* open stream and retrieve first file */  
	    dirp->search_handle = FindFirstFile (dirp->patt, &dirp->current.data);  
	    if (dirp->search_handle == INVALID_HANDLE_VALUE) {  
	      /* invalid search pattern? */  
	      free (dirp);  
	      return NULL;  
	    }  
  
	    /* there is an un-processed directory entry in memory now */  
	    dirp->cached = 1;  
  
	  }  
	  return dirp;  
	}  

I found that adding the free to the end of the listDir function in ofxDirList.cpp stops the leak…

  
int ofxDirList::listDir(string directory){  
    directory = ofToDataPath(directory);  
  
	nameArray.clear();  
	pathArray.clear();  
  
    if(directory.length() <= 0)return 0;  
  
    //if the trailing slash was not added - then add it  
	if( directory[directory.length()-1] != '/'){  
        directory = directory + "/";  
	}  
  
	DIR *dir = NULL;  
	struct dirent *entry;  
  
    //open the directory  
    ofLog(OF_LOG_VERBOSE, "ofxDirList - attempting to open %s", directory.c_str());  
    dir = opendir(directory.c_str());  
  
	if(dir == NULL){  
		ofLog(OF_LOG_ERROR, "ofxDirList - error opening directory");  
		return 0;  
	}else{  
		ofLog(OF_LOG_VERBOSE, "ofxDirList - success opening directory");  
	}  
  
    string entry_name = "";  
    string ext = "";  
	bool skip = false;  
  
	while ((entry = readdir(dir)) != NULL){  
  
        //turn it into a C++ string  
        entry_name = entry->d_name;  
  
        //lets get the length of the string here as we query it again  
        int fileLen = entry_name.length();  
  
		if(fileLen <= 0)continue; //if the name is not existant  
		if(entry_name[0] == '.')continue; //ignore invisible files, ./ and ../  
  
		//by default we don't skip files unless we are checking extensions  
		skip = false;  
  
		if(allowedFileExt.size() > 0){  
			//we will skip this files unless it has an allowed extension  
			skip = true;  
			for(int i = 0; i < (int)allowedFileExt.size(); i++){  
  
				//if the wildecard * has been entered for an ext type then don't check any extensions  
				if( allowedFileExt[i] == "*"){ skip = false; break; }  
  
  
				int extLen = allowedFileExt[i].length();  
  
				//the extension has to be shorter than the filename - simple check  
				if(extLen >= fileLen) continue;  
  
                //lets get the ext as lowercase  
                ext = strToLower( getExt(entry_name) );  
  
                //if no ext - then skip this ext check  
                if( ext == "" )continue;  
  
                //if we find a match then stop checking and approve this file  
                if(ext == allowedFileExt[i]){  
                    skip = false;  
                    break;  
                }  
			}  
		}  
  
		if(skip) continue;  
  
		//finally we store the result  
        pathArray.push_back(directory + entry_name);  
        nameArray.push_back(entry_name);  
  
		ofLog(OF_LOG_VERBOSE, "ofxDirList - listing %s ", nameArray.back().c_str());  
	}  
  
	free(dir);  
  
	ofLog(OF_LOG_VERBOSE, "ofxDirList - listed %i files in %s", nameArray.size(), directory.c_str());  
	return nameArray.size();  
}  

Darren

Definitely post this as an issue on the OF github:

http://github.com/openframeworks/openFrameworks/issues

I think this is fixed in:
http://github.com/openframeworks/openFr-…-t.cpp#L141

we just check that the dir is not NULL and if so close it.

  
	if(dir != NULL) closedir(dir);