3

We have programed a suite of codes in C which takes Matlab data files (.mat) in a dir as input, and it also calls GSL functions to search for the roots of a polynormial and generate random numbers as such. We are working on OSX. We used Valgrind to check if there are any memory leaks since we used quite lots of malloc and free in the codes. And it indeed helped us a lot in finding memory leaks at many places. However, there are still one that we cannot fix. The problem exists in the function listfileswext(it lists all files in a directory with a given extension, i.e. .mat) in the subroutine called maxphaseutils.c:

char ** listfileswext (const char *ext, const char *dirName, size_t *nFiles, size_t *maxFileNameLen)
{
    /*printf("------- %s -------\n",ext);
    printf("Extension string length %zu\n",strlen(ext));*/
  char *pattern = (char *)malloc((3+strlen(ext))*sizeof(char));
  DIR *dp;
  struct dirent *ep;
  char **fileList;
  size_t lpc;

  pattern[0] = '*';
  pattern[1] = '.';
  pattern[2] = '\0';
  strcat(pattern,ext);

  /*printf("Pattern %s\n",pattern);*/
  /* Step 1: Count the number of files with the required 
     extension.
  */
  size_t countValidFiles = 0;
  dp = opendir(dirName);
  if (dp != NULL){
      while ((ep = readdir(dp))){
            /*printf("Checking file %s\n",ep->d_name);*/
            if(!fnmatch(pattern, ep->d_name, (FNM_FILE_NAME|FNM_PERIOD))){
                /* Match. Increment counter */
                /*printf("found match with pattern %s\n",pattern);*/
                countValidFiles++;
            }
      }
      (void) closedir (dp);
      /*
        Apparently, there is no need to free ep as it is declared to be 'static' in the readdir function
      */
  }
  else{
    printf ("Couldn't open the directory %s\n",dirName);
    free(pattern);
    return NULL;
  }
  *nFiles = countValidFiles;
  /* Step 2: Create storage for list of filenames */
  fileList = (char **)malloc(countValidFiles*sizeof(char *));
  /* Can't find a better way than to repeat the whole loop again */
  countValidFiles = 0;
  dp = opendir(dirName);
  if (dp != NULL){
      while ((ep = readdir(dp))){
            if(!fnmatch(pattern, ep->d_name, (FNM_FILE_NAME|FNM_PERIOD))){
                fileList[countValidFiles] = (char *)malloc(strlen(ep->d_name)*sizeof(char));
                strcpy(fileList[countValidFiles],ep->d_name);
                /* Match. Increment counter */
                countValidFiles++;
            }
      }
      (void) closedir (dp);
  }
  else{
    printf ("Couldn't open the directory %s\n",dirName);
    return NULL;
  }

    /*Find longest filename */
    size_t fileNameLen;
    *maxFileNameLen = 0;
    size_t lpc1;
    for (lpc1 = 0; lpc1 < *nFiles; lpc1++){
        fileNameLen = strlen(fileList[lpc1]);
        if ( fileNameLen > *maxFileNameLen)
            *maxFileNameLen = fileNameLen;
    }

  /* Wrap up */
  free(pattern);
  return fileList;
}   

In this function, the variable fileList is called

char **inputFileList;
    size_t nInputFiles, maxFileNameLen;
    inputFileList = listfileswext("mat", simDataDir, &nInputFiles, &maxFileNameLen);

and then freed

for(lpc1 = 0; lpc1 < nInputFiles; lpc1++){
        /* Free up dynamically allocated memory for file list*/
        free(inputFileList[lpc1]);
    }
    /* Free up dynamically allocated memory */
free(inputFileList);

in main function as shown above. As you can see that fileList is freed as inputFileList in main rather than in the function (listfileswext) where is allocated. We think it's OK. After running Valgrind, it shows

==8643== Invalid write of size 8
==8643==    at 0x101921031: _platform_memmove$VARIANT$Unknown (in /usr/lib/system/libsystem_platform.dylib)
==8643==    by 0x1016E33AD: stpcpy (in /usr/lib/system/libsystem_c.dylib)
==8643==    by 0x101755F96: __strcpy_chk (in /usr/lib/system/libsystem_c.dylib)
==8643==    by 0x1000044B2: listfileswext (maxphaseutils.c:153)
==8643==    by 0x100005FBD: main (perfeval_snglproc.c:41)
==8643==  Address 0x104c6381d is 13 bytes inside a block of size 20 alloc'd
==8643==    at 0x100010EBB: malloc (vg_replace_malloc.c:303)
==8643==    by 0x10000447C: listfileswext (maxphaseutils.c:152)
==8643==    by 0x100005FBD: main (c:41)

and

==8643== Invalid read of size 8
==8643==    at 0x101921040: _platform_memmove$VARIANT$Unknown (in /usr/lib/system/libsystem_platform.dylib)
==8643==    by 0x101756127: __strcat_chk (in /usr/lib/system/libsystem_c.dylib)
==8643==    by 0x1000060CE: main (perfeval_snglproc.c:67)
==8643==  Address 0x104c63224 is 4 bytes inside a block of size 11 alloc'd
==8643==    at 0x100010EBB: malloc (vg_replace_malloc.c:303)
==8643==    by 0x10000447C: listfileswext (maxphaseutils.c:152)
==8643==    by 0x100005FBD: main (perfeval_snglproc.c:41)

Here perfeval_snglproc.c is the main. Besides, there are bunch of staffs as follows which seem nothing to do with the functions we made (we may have no control on these system files):

==8643== 168 bytes in 7 blocks are possibly lost in loss record 657 of 1,081
==8643==    at 0x10001178B: malloc_zone_calloc (vg_replace_malloc.c:717)
==8643==    by 0x1019C737C: NXHashInsert (in /usr/lib/libobjc.A.dylib)
==8643==    by 0x1019C746F: _NXHashRehashToCapacity (in /usr/lib/libobjc.A.dylib)
==8643==    by 0x1019C73B9: NXHashInsert (in /usr/lib/libobjc.A.dylib)
==8643==    by 0x1019D6687: realizeClass(objc_class*) (in /usr/lib/libobjc.A.dylib)
==8643==    by 0x1019D5B53: realizeClass(objc_class*) (in /usr/lib/libobjc.A.dylib)
==8643==    by 0x1019CA38D: look_up_class (in /usr/lib/libobjc.A.dylib)
==8643==    by 0x1019CA1B9: objc_getFutureClass (in /usr/lib/libobjc.A.dylib)
==8643==    by 0x101D51D3F: __CFInitialize (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==8643==    by 0x7FFF5FC12BC7: ImageLoaderMachO::doImageInit(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==8643==    by 0x7FFF5FC12E8C: ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==8643==    by 0x7FFF5FC0F890: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==8643== 
==8643== 168 (32 direct, 136 indirect) bytes in 1 blocks are definitely lost in loss record 658 of 1,081
==8643==    at 0x10001117C: malloc_zone_malloc (vg_replace_malloc.c:305)
==8643==    by 0x101D6FF79: CFUniCharGetUnicodePropertyDataForPlane (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==8643==    by 0x101D6FEBE: CFUniCharGetNumberOfPlanesForUnicodePropertyData (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==8643==    by 0x101D6F9A3: __CFUniCharLoadDecompositionTable (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==8643==    by 0x101D6F048: CFUniCharDecompose (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==8643==    by 0x101D681CE: CFStringGetFileSystemRepresentation (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==8643==    by 0x101E91929: _CFURLCreateWithFileSystemPath (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==8643==    by 0x101D693D9: _CFBundleCopyBundleURLForExecutableURL (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==8643==    by 0x101D63DE4: _CFBundleGetMainBundleAlreadyLocked (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==8643==    by 0x101D63D5A: CFBundleGetMainBundle (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==8643==    by 0x101D8C0A7: _CFPrefsGetCacheStringForBundleID (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==8643==    by 0x101EDADC8: __50+[CFPrefsSearchListSource withSnapshotSearchList:]_block_invoke (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)

Please help! Thanks in advance!

ywang
  • 101
  • 3
  • 8

1 Answers1

2

According to this, the leaks are not caused by your program, but by system libraries.

For the errors, when allocating space for c-string, you need to make space for trailing zero, so change

 fileList[countValidFiles] = (char *)malloc(strlen(ep->d_name)*sizeof(char));

to

 fileList[countValidFiles] = (char *)malloc((strlen(ep->d_name) + 1)*sizeof(char));
Community
  • 1
  • 1
mausik
  • 77
  • 5
  • 1
    `sizeof(char)` is always 1 **by definition** so you can omit those (see [C99 §6.5.3.4 number 3](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf): _When applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1._) – DarkDust Apr 17 '16 at 17:58
  • There are platforms where char has different size, look at [this question](http://stackoverflow.com/questions/2098149/what-platforms-have-something-other-than-8-bit-char). – mausik Apr 17 '16 at 18:39
  • Yes, but `sizeof(char)` will also return 1 for platforms where `CHAR_BIT` > 8. That's because the sizes here are in _bytes_ and `CHAR_BIT` defines the _size of one byte_. See also [this question](http://stackoverflow.com/questions/2215445/are-there-machines-where-sizeofchar-1-or-at-least-char-bit-8?lq=1), [this question](http://stackoverflow.com/questions/437470/type-to-use-to-represent-a-byte-in-ansi-c89-90-c/437640#437640), [C FAQ entry](http://c-faq.com/charstring/wchar.html). So on a machine with `CHAR_BIT == 16`, `malloc(1)` would allocate at least 16 bits, `malloc(2)` at least 32 bits… – DarkDust Apr 17 '16 at 19:03