Search code examples
cprogram-entry-pointrealloc

c program fails if i put argc/argv to main function without using them


I wrote a function that converts a string to an array of strings. The test program works fine until I replace int main() with int main(int argc, char** argv)

Console:

*** glibc detected *** ./a.out: realloc(): invalid pointer: 0xbfdc6370 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x75ee2)[0xb764eee2]
/lib/i386-linux-gnu/libc.so.6(realloc+0x25d)[0xb765355d]
/lib/i386-linux-gnu/libc.so.6(realloc+0x273)[0xb7653573]
./a.out[0x80485d6]
./a.out[0x80486bf]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75f24d3]
./a.out[0x8048461]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:05 2889457    /home/tg/a.out
08049000-0804a000 r--p 00000000 08:05 2889457    /home/tg/a.out
0804a000-0804b000 rw-p 00001000 08:05 2889457    /home/tg/a.out
085cc000-085ed000 rw-p 00000000 00:00 0          [heap]
b75a5000-b75c1000 r-xp 00000000 08:05 5637044    /lib/i386-linux-gnu/libgcc_s.so.1
b75c1000-b75c2000 r--p 0001b000 08:05 5637044    /lib/i386-linux-gnu/libgcc_s.so.1
b75c2000-b75c3000 rw-p 0001c000 08:05 5637044    /lib/i386-linux-gnu/libgcc_s.so.1
b75d8000-b75d9000 rw-p 00000000 00:00 0 
b75d9000-b777c000 r-xp 00000000 08:05 5636109    /lib/i386-linux-gnu/libc-2.15.so
b777c000-b777d000 ---p 001a3000 08:05 5636109    /lib/i386-linux-gnu/libc-2.15.so
b777d000-b777f000 r--p 001a3000 08:05 5636109    /lib/i386-linux-gnu/libc-2.15.so
b777f000-b7780000 rw-p 001a5000 08:05 5636109    /lib/i386-linux-gnu/libc-2.15.so
b7780000-b7783000 rw-p 00000000 00:00 0 
b7797000-b779a000 rw-p 00000000 00:00 0 
b779a000-b779b000 r-xp 00000000 00:00 0          [vdso]
b779b000-b77bb000 r-xp 00000000 08:05 5636227    /lib/i386-linux-gnu/ld-2.15.so
b77bb000-b77bc000 r--p 0001f000 08:05 5636227    /lib/i386-linux-gnu/ld-2.15.so
b77bc000-b77bd000 rw-p 00020000 08:05 5636227    /lib/i386-linux-gnu/ld-2.15.so
bfda7000-bfdc8000 rw-p 00000000 00:00 0          [stack]
Aborted (core dumped)

Code:

/* tokenize function*/
int tokenize(char ***tokenList, char *string, char *separators){
    /* initialization */
    int count = 0;                      // token counter
    int length = strlen(string) + 1;    // length of string array
    int lengthSep = strlen(separators); // number of separators
    char *memory = malloc(length);      // copy of string; string token array in the end
    if (memory == NULL)                 // error treatment for malloc
        return -1;
    memcpy(memory, string, length);
    char *lastPos = memory;             // start position of the current string token in memory
    char **tempList;                    // temporary pointer to token array

    /* find occurences of separators and replace them with '\0', reallocate tempList for each new string token built in that way */
    for (int i = 0; i < length; i++){
        /* check if current character is a separator */
        for (int j = 0; j <= lengthSep; j++){
            if (*(memory + i) == separators[j]){
                count++;                            // increase string counter
                *(memory + i) = '\0';               // replace separator by '\0'
                tempList = realloc(tempList, sizeof(char*) * count);    // reallocate tempList
                if (tempList == NULL){              // error treatment for realloc
                    free(memory);
                    free(tempList);
                    return -1;
                }                                   
                tempList[count-1] = lastPos;        // add pointer to the new string to the end of tempList
                lastPos = memory + i + 1;           // calculate starting position for the next string token
                break;                              // escape from inner loop (found matching separator)
            }
        }
    }
    *tokenList = tempList;
    return count;
}
int main(){
    char string[100] = "aa/bbb/cccc";
    char separators[2] = "/";
    char **tokenList;
    int count;
    count = tokenize(&tokenList,string, separators);
    printf("count: %d\n", count);
    printf("item: %s\n", tokenList[0]);
    return EXIT_SUCCESS;

}

Solution

  • You don't initialise tempList so the first time you call tempList = realloc(tempList,... you're attempting to extend/free an arbitrary address.

    The easiest fix is simply to initialise tempList to NULL

    char **tempList = NULL;
    

    As an aside, the code

    tempList = realloc(tempList, sizeof(char*) * count);
    if (tempList == NULL){
        free(memory);
        free(tempList);
        return -1;
    }
    

    contains another small bug. If realloc fails and tempList is NULL, you've leaked the previous value of tempList and calling free(tempList) does nothing. If you want to properly handle out of memory errors, you'd need to do something like

    void* tmp = realloc(tempList, sizeof(char*) * count);
    if (tmp == NULL){
        free(memory);
        free(tempList);
        return -1;
    }
    tempList = tmp;