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):
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();
}