Search code examples
crealloc

Using realloc on a char * within an array alters data outside of that array


I'm observing some really weird behavior regarding realloc .... I was wondering if y'all could help me.

I have an array of dynamically allocated char *'s called "frags". I also have a char * called "combination" which points to some string literal that represents a new fragment. I want to replace one of the fragments within "frags" with the contents of "combination." The way my project is structured, I am sending the frags array, index of to-be-replaced frag, and combination string into a function. Within this function I have:

printf("combination before realloc: %s\n", combination);
char *newString = (char *) realloc(frags[firstIndex], strlen(combination) + 1);
assert(newString != NULL);
printf("combination after realloc: %s\n", combination);


strcpy(newString, combination);
frags[firstIndex] = newString;

Oddly, the printf's do not print the same thing. The first printf yields "hellol" which is correct, but the next printf yields jibberish - something like "{?`?p??". Thus, the problem resides in the call to realloc. And I honestly have no idea what's going on. It seems the very call to realloc has messed with combination somehow, but I thought that if that could possibly happen then it would return NULL?

Please help me :(

Edit: Adding code

bool findMaxOverlap(char *first, char *second, char **combination, int *roundMax) {
    // setup lng and shrt
    char *lng, *shrt;
    if (strlen(first) >= strlen(second)) { lng = first; shrt = second; }
    else { lng = second; shrt = first; }
    int shrtLen = strlen(shrt), lngLen = strlen(lng);

    // check if lng contains shrt
    if (strstr(lng, shrt) != NULL && shrtLen > *roundMax) {  
        *combination = lng;
        *roundMax = shrtLen;
        return true;
    }
    else // check if lng's tail ends contain part of shrt

    {                              
        int numChars = shrtLen - 1, max = 0, shrtOffset = 0, lngOffset = 0;
        for (int i = 0; i < shrtLen && numChars > *roundMax && numChars > max; i++) {
            numChars = shrtLen - 1 - i;
            for (int j = 0; j < lngLen; j++) {
                if (strncmp(shrt + i, lng + j, numChars) == 0) {
                    max = numChars;
                    shrtOffset = i;
                    lngOffset = j;
                }
            }
        }
        if (shrtOffset > lngOffset) {
            // short first
            char newFrag[lngLen + shrtOffset + 1];  
            strncpy(newFrag, shrt, shrtOffset);
            strcat(newFrag, lng + shrtOffset);
            *combination = newFrag;
            *roundMax = numChars;
            return true;
        } else {
            // lng first

            char newFrag[lngLen + (shrtLen - numChars) + 1];
            strcpy(newFrag, lng);
            strcat(newFrag, shrt + numChars);

            *combination = newFrag;
            printf("combination in findmax is: %s\n", *combination);
            *roundMax = numChars;
            return true;
        }
    }
    return false;
}

void mergeFrags(char *frags[], int index1, int index2, char *combination) {

    int firstIndex, secondIndex;
    if (index1 < index2) {
        firstIndex = index1;
        secondIndex = index2;
    } else {
        firstIndex = index2;
        secondIndex = index1;
    }

    char temp[strlen(combination) + 1];
    strcpy(temp, combination);

    char *newString = (char *) realloc(frags[firstIndex], strlen(combination) + 1);
    assert(newString != NULL);

    strcpy(newString, temp);
    frags[firstIndex] = newString;
    free(frags[secondIndex]);

}

char *reassemble(char *frags[], int numFrags) {

    if (numFrags > 1) {
        char *combination;
        int max, index1, index2, currNumFrags = numFrags;

        for (int currentRound = 0; currentRound < numFrags - 1; currentRound++) {
            max = index1 = index2 = 0, combination = NULL;

            for (int i = 0; i < currNumFrags; i++) {
                for (int j = i+1; j < currNumFrags; j++) {
                    //find max overlap of pair
                    if (findMaxOverlap(frags[i], frags[j], &combination, &max)) {
                        printf("round #: %d, combination: %s, max: %d\n", currentRound, combination, max);
                        index1 = i; index2 = j;
                    } 
                }
            }
            // merge 

            mergeFrags(frags, index1, index2, combination);
            currNumFrags--;
        }
    }


    return frags[0];
}

Solution

  • You said (in the comments above) that you were using strdup to allocate the data in combination, but what you're really doing is setting combination to point to data that's on the stack. After findMaxOverlap returns, you are now pointing at unallocated space on the stack, and this provides you with the undefined behavior you're seeing. When realloc is called, the area in the stack is reused, and the value of combination looks like garbage.