LibAIFF CloseFile: Pointer being freed was not all

2019-03-04 14:18发布

问题:

I have written a piece of code that attempts to search a directory and its subfolders for two AIFF files and using the LibAIFF library to import and then perform some processing operations on them.

Part 1: Searching the directory for the files

For this part of the program, I need to look for the files (which can be thought of as identical AIFF files except for a difference in their filenames) with known names (for example SineSweepA.aiff and SineSweepB.aiff) and then construct the absolute path to it (the length of which I am unaware of (since my program needs to work on different computers where the AIFFs can be located within different subfolders within a MainDirectory - see code below) but know will be less than 200 characters in length). I am able to do this successfully and consistently using the following piece of code:

void file_search(char* parentDir, char* subFolder, char* filenamePrefix, char* tempString, char* tempFilepath, int* foundFlag, int* level);
int32_t *import_sweeps(char* sweepFilepath, uint64_t* numSamples, int* numChannels, double* samplingRate, int* bitDepth, int* segmentSize, int* importFlag);

int main()
{
    ...
    char MainDirectory[200] = "/Users/rrr/Documents/Foldername1/";
    char tempFilepath[200], tempFilepathR[200], parentDir[200], filenamePrefix[200], subFolder[200], tempString[200]; 
    int level = 0, foundFlag = 0;
    int numChannels = 0;
    int bitDepth;
    int segmentSize;
    int importFlag = 0;
    int32_t *sweepRfile = NULL;
    uint64_t numSamples = 0, numSamplesR = 0;
    unsigned long templen;
    double samplingRate = 0.0;
    char *sweepFilepath = NULL, *sweepFilepathR = NULL; // Allocated to specific size later
    strcpy(parentDir, MainDirectory);
    strcat(parentDir, "SubFolderName1/");
    strcpy(tempFilepathR, parentDir);
    strcpy(filenamePrefix, "KnownFilenamePrefix1");

    // file_search() searches for a specific file with a known name and constructs the absolute path to the file and stores it in tempFilepathR. The function is shown further below.
    file_search(parentDir, subFolder, filenamePrefix, tempString, tempFilepath, &foundFlag, &level);

    if (foundFlag)
    {
        sprintf(tempFilepath, "%s%s/KnownFilenamePrefix1%s.aiff", parentDir, subFolder, subFolder);
        sprintf(tempFilepathR, "%s%s/KnownFilenamePrefix2%s.aiff", parentDir, subFolder, subFolder);
    }
    ...

    (to be continued in Part 2 of my question below)
}

void file_search(char* dir, char* subfolder, char* fileprefix, char* filename, char* filepath, int*flag, int* level)
{
    DIR *dp;
    struct dirent *entry; // entry is a pointer to the structure "dirent" defined in <dirent.h>
    struct stat statbuf; // the structure "stat" is defined in <stat.h>
    if((dp = opendir(dir)) == NULL) {
        fprintf(stderr,"Cannot open directory: %s\n", dir);
        return;
    }
    chdir(dir); // this sets the working directory to the string pointed to by "dir"
    while((entry = readdir(dp)) != NULL)
    {
        lstat(entry->d_name, &statbuf);
        if(S_ISDIR(statbuf.st_mode)) // Tests for a directory
        {
            // Found a directory
            if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)
            {
                // Ignore . and ..
                continue;
            }

            if(level[0] < 1)
            {
                // Proceed down one level and search again
                strcpy(subfolder,entry->d_name);
                level[0] = level[0] + 1;

                // Recursive function call
                file_search(entry->d_name, subfolder, fileprefix, filename, filepath, postfilepath, flag, level);

                level[0] = level[0] - 1;

                if(flag[0] == 1)
                {
                    // Exit loop if a file was found at a lower level
                    break;
                }
            }
        }
        else
        {
            sprintf(filename, "%s%s.aiff", fileprefix, subfolder);
            if(strcmp(entry->d_name,filename) == 0)
            {
                // File found. Construct absolute path to file
                sprintf(filepath, "%s%s/%s", filepath, subfolder, filename); // Pass filepath outside
                flag[0] = 1; //Appropriate file found
                break;
            }
        }
    }
    chdir("..");
    closedir(dp);
}

So by using the above code, I am able to successfully search for two AIFF files with given filenames by searching through subfolders with a known MainDirectory, construct their absolute paths and store them in tempFilepath and tempFilepathR. The next step is to import these two files and this is where I run into a problem.

Part 2: Importing the files

The problem I run into is as follows: I implemented the LibAIFF library to import the files. The issue is that if I run the program, say N times, then on some of the runs, the first file gets imported but not the second, on other runs the second gets imported but not the first (note that if the first doesn't get imported, the program stops). Before I explain the error, please know that there is no issue with the AIFF files, for the sake of this problem you can assume they are identical and that even their absolute paths and filenames are identical except one has a suffix A.aiff and the other B.aiff. These file paths are stored as strings in identically defined variables (tempFilepath and tempFilepathR).

Here is the rest of the necessary part of my code continued from above

int main()
{
    // Continued from above
    ...

    // Copy over exact file paths (I had to do this because the function AIFF_OpenFile which is part of the LibAIFF library and shown below refused to accept a statically allocated char variable such as tempFilepath)

        templen = strlen(tempFilepathR); // tempFilepath and tempFilepathR always have the same length
        sweepFilepath = malloc(templen + 1);
        strcpy(sweepFilepath, tempFilepath);

        // Proceed to import the FIRST AIFF (returned to sweepRfile from import_sweeps())
        sweepRfile = import_sweeps(sweepFilepath, &numSamples, &numChannels, &samplingRate, &bitDepth, &segmentSize, &importFlag);
        if (importFlag) // The import was successful
        {
            free(sweepFilepath);
            // Do some processing with the successfully imported AIFF
            free(sweepRfile);
        }
        else // The import was unsuccessful and sweepRfile (which is usually malloc'ed in the import_sweeps() function is not malloc'ed
        {
            free(sweepFilepath);
        }

        // Now for the SECOND AIFF (I can overwrite a lot of the variables used for the first AIFF because I don't need them)
        sweepFilepathR = malloc(templen + 1); // templen is assigned above
        strcpy(sweepFilepathR, tempFilepathR);

        // Proceed to import the SECOND AIFF (returned to sweepRfile from import_sweeps())
        sweepRfile = import_sweeps(sweepFilepathR, &numSamplesR, &numChannels, &samplingRate, &bitDepth, &segmentSize, &importFlag);
        if (importFlag) // The import was successful
        {
            free(sweepFilepathR);
            // Do some processing with the successfully imported AIFF
            free(sweepRfile);
        }
        else // The import was unsuccessful and sweepRfile (which is usually malloc'ed in the import_sweeps() function is not malloc'ed
        {
            free(sweepFilepathR);
        }
    ...
    // Rest of code in main is irrelevant because it doesn't even get there.
}

The break always occurs within the import_sweeps() function (sometimes for the first AIFF and sometimes for the second). The function is shown below

int32_t *import_sweeps(char* sweepFilepath, uint64_t* numSamples, int* numChannels, double* samplingRate, int* bitDepth, int* segmentSize, int* importFlag)
{
    // Initialize files for importing */
AIFF_Ref fileref;

// Import Routine */
fileref = AIFF_OpenFile(sweepFilepath, F_RDONLY);
if(fileref)
{
    // File opened successfully. Proceed to intialize files for getting information about AIFF file
    uint64_t nSamples;
    int nSamplePts, channels, bitsPerSample, segSize, temp;
    double smpr;

    // Get AIFF file format details
    temp = AIFF_GetAudioFormat(fileref, &nSamples, &channels, &smpr, &bitsPerSample, &segSize);
    if (temp < 1) {
        fprintf(stderr,"Error getting audio format.\n");
        AIFF_CloseFile(fileref);
        return (int32_t) 0;
    }
    else
    {
        numSamples[0] = nSamples;
        samplingRate[0] = smpr;
        numChannels[0] = channels;
        bitDepth[0] = bitsPerSample;
        segmentSize[0] = segSize;
        nSamplePts = ((int) nSamples)*channels;
        int32_t *samples = malloc((nSamplePts+1) * sizeof(int32_t));

        // Read AIFF
        temp = AIFF_ReadSamples32Bit(fileref, samples, nSamplePts);
        if (temp != -1)
        {
            AIFF_CloseFile(fileref);
            importFlag[0] = 1;
            return samples;
        }
        else
        {
            fprintf(stderr,"Unable to read AIFF.\n");
            AIFF_CloseFile(fileref);
            return (int32_t) 0;
        }
    }
}
else
{
    fprintf(stderr,"Unable to open AIFF file.\n");
}
return (int32_t) 0;
}

Inside import_sweeps() above, the AIFF file is ALWAYS successfully read by calling the function AIFF_ReadSamples32Bit(fileref, samples, nSamplePts);. Therefore, the temp value is never -1. Whenever an error (as described above and I will give the actual error message below) happens, it ALWAYS occurs when it tries to call AIFF_CloseFile(fileref);.

Shown below are the functions AIFF_ReadSamples32Bit and AIFF_CloseFile as defined in the LibAIFF library.

int AIFF_ReadSamples32Bit(AIFF_Ref r, int32_t * samples, int nSamplePoints)
{
int n = nSamplePoints;
void *buffer;
int i, j;
size_t h;
size_t len;
int segmentSize;
int32_t *dwords;
int16_t *words;
int8_t *sbytes;
uint8_t *inbytes;
uint8_t *outbytes;
uint8_t x, y, z;

if (!r || !(r->flags & F_RDONLY))
    return -1;
if (n % (r->nChannels) != 0)
    return 0;

if (n < 1 || r->segmentSize == 0) {
    if (r->buffer) {
        free(r->buffer);
        r->buffer = NULL;
        r->buflen = 0;
    }
    return -1;
}
segmentSize = r->segmentSize;
len = (size_t) n * segmentSize;

if ((r->buflen) < len) {
    if (r->buffer)
        free(r->buffer);
    r->buffer = malloc(len);
    if (!(r->buffer)) {
        return -1;
    }
    r->buflen = len;
}
buffer = r->buffer;

h = AIFF_ReadSamples(r, buffer, len);
if (h < (size_t) segmentSize) {
    free(r->buffer);
    r->buffer = NULL;
    r->buflen = 0;
    return 0;
}
n = (int) h;
if (n % segmentSize != 0) {
    free(r->buffer);
    r->buffer = NULL;
    r->buflen = 0;
    return -1;
}
n /= segmentSize;

switch (segmentSize) {
case 4:
    dwords = (int32_t *) buffer;
    for (i = 0; i < n; ++i)
        samples[i] = dwords[i];
    break;
case 3:
    inbytes = (uint8_t *) buffer;
    outbytes = (uint8_t *) samples;
    n <<= 2;    /* n *= 4 */
    j = 0;

    for (i = 0; i < n; i += 4) {
        x = inbytes[j++];
        y = inbytes[j++];
        z = inbytes[j++];
#ifdef WORDS_BIGENDIAN
        outbytes[i] = x;
        outbytes[i + 1] = y;
        outbytes[i + 2] = z;
        outbytes[i + 3] = 0;
#else
        outbytes[i] = 0;
        outbytes[i + 1] = x;
        outbytes[i + 2] = y;
        outbytes[i + 3] = z;
#endif
    }

    n >>= 2;
    break;
case 2:
    words = (int16_t *) buffer;
    for (i = 0; i < n; ++i) {
        samples[i] = (int32_t) (words[i]) << 16;
    }
    break;
case 1:
    sbytes = (int8_t *) buffer;
    for (i = 0; i < n; ++i) {
        samples[i] = (int32_t) (sbytes[i]) << 24;
    }
    break;
}

return n;
}

and

int AIFF_CloseFile(AIFF_Ref ref)
{
int r;

if (!ref)
    return -1;
if (ref->flags & F_RDONLY) {
    AIFF_ReadClose(ref); // BREAK OCCURS HERE EVERYTIME
    r = 1;
} else if (ref->flags & F_WRONLY) {
    r = AIFF_WriteClose(ref);
} else {
    r = -1;
}

return r;
}   

The break occurs at AIFF_ReadClose(ref); EVERYTIME. So I have also shown this function below.

static void AIFF_ReadClose(AIFF_Ref r)
{
if (r->buffer)
    free(r->buffer);
if (r->buffer2)
    free(r->buffer2);  // THIS IS WHERE THE BREAK OCCURS EVERYTIME
Unprepare(r);
fclose(r->fd);
free(r);
return;
}

The break always occurs as shown above. The following is the error message: (25693,0x7fff7db87310) malloc: * error for object 0x4000000000000000: pointer being freed was not allocated * set a breakpoint in malloc_error_break to debug

So basically, the above error occurs unpredictably. When it doesn't occur, my code works perfectly. Any help as to how I might solve this problem is much appreciated.

IF ANYONE IS WILLING TO DOWNLOAD THE LIBAIFF LIBRARY TO INVESTIGATE FURTHER AND HELP ME OUT, the link to the library is: http://aifftools.sourceforge.net/libaiff/.

Thanks in advance for any suggestions!

回答1:

1, please confirm buffer2 has been initialized with NULL before using. In all your pasted codes, I can not find any assignment or memory allocation for buffer2.

2, please assign the pointer with NULL after calling free, like:

if (r->buffer)
{
    free(r->buffer);
    r->buffer = NULL; 
}
if (r->buffer2)
{
    free(r->buffer2);
    r->buffer2 = NULL; 
}

If all this can not resolve you problem, please give more code about buffer2.