Subject: free() vs realloc() on cygwin
From: "Max" <[email-masked]>
To: [email-masked]
Date: Sat, 22 Jun 2002 09:56:28 -0400
Newsgroups: gmane.os.cygwin

Hi,

I ran into an issue that I thought was strange while doing some C
development on cygwin 1.3.10 with gcc 2.95.3-5.

For one section of code I have, I found that if I used free() to try and
free the memory I had asked for with
malloc() or calloc(), my program died with signal 11 ... but if I changed
the call to use realloc(), the program
ran just fine.

I tried running the program I am developing on FreeBSD and there were no
problems with the free() call on
that OS ...

Does this sound like a Cygwin quirk or am I just missing something with my
C?

Here is the code ... newargv(), makeargv(), then freeargv() (Adapted from
Practical UNIX Programming) ...

Any help appreciated .. and please let me know if I am not posting this to
the proper place.

Thank you.

Max

Example usage:

char ***argvp = NULL;
char *cmd = "ls -al /etc/hosts";

argvp = newargv();

makeargv(cmd, " ", NOTOKENS, argvp);

// ... work on argvp

freeargv(argvp);

=====================

char ***newargv() {

    char ***ptr = (char ***) malloc(sizeof(char ***));

    if (ptr == NULL)
        perror("ARGV malloc");

    return ptr;

}

void freeargv(char ***argvp, int len) {

    int i = 0;
    char *ptr_addr = NULL;

    debug("freeing argvp");

    for (i = (len - 1); i >= 0; i--) {
        ptr_addr = *((*argvp) + i);
        debug("Free char * ptr %d s(%s), x(%x)", i, ptr_addr, &ptr_addr);
        realloc(ptr_addr, 0); <<<<<-- USING free() causes program to die
with signal 11 on cygwin!
    }

    debug("Free base ptr");
    realloc(*argvp, 0); <<<<<-- USING free() causes program to die with
signal 11 on cygwin!

}

/*
   Make argv array (*argv) for tokens in s which are separated
   by delimiters.  Return -1 on error or the number of tokens otherwise.
   */

int makeargv(char *s, char *delimiters, int flags, char ***argvp) {

    char *t;
    char *snew;
    int numtokens;
    int i;

    /* snew is real start of string after skipping leading delimiters */
    snew = s + strspn(s, delimiters);

    /* create space for a copy of snew in t */
    if ((t = calloc(strlen(snew) + 1, sizeof(char))) == NULL) {
        *argvp = NULL;
        numtokens = -1;
    } else {

        strcpy(t, snew);

        if (estrtok(t, delimiters, flags) == NULL) {
            numtokens = 0;
        } else {

            for (numtokens = 1; estrtok(NULL, delimiters, flags) != NULL;
                                numtokens++)
                ;

            debug("We have %d tokens", numtokens);

            /* Create an argument array to contain ptrs to tokens */

            if ((*argvp = calloc(numtokens + 1, sizeof(char *))) == NULL) {
                debug("Calloc == NULL");
                free(t);
                numtokens = -1;
            } else {
                debug("Calloc != NULL");
                if (numtokens > 0) {
                    strcpy(t, snew);
                    **argvp = estrtok(t, delimiters, flags);
                    for (i = 1; i < numtokens + 1; i++) {
                        *((*argvp) + i) = estrtok(NULL, delimiters, flags);
                    }
                } else {
                    **argvp = NULL;
                    free(t);
                }
            }
        }
    }

    return numtokens;

}

char *estrtok(char *src, const char *delimiters, int flags) {

    static char **work = NULL;

    char *tok;

    if (src != NULL) {

        if (work != NULL) {
            free(work);
        }

        work = (char **) malloc(sizeof(char **));

        if (work == NULL) {
            perror("Malloc static char ** failed");
            return NULL;
        }

    }

    tok = estrtok_r(src, delimiters, flags, work);

    debug("After estrtok_r: work points at %x (%x)", work, *work);

    return tok;

}

char *estrtok_r(char *src, const char *delimiters, int flags, char **lasts)
{

    char *tok = NULL;

    int i = 0;

    int length = -1;

    if (lasts == NULL) {
        fprintf(stderr, "User supplied char ** NULL!\n");
        return NULL;
    }

    /* If src is not NULL, clear work area if it is initialized */
    if (src != NULL) {

        *lasts = src;

        debug("New estrtok, lasts is: %x (%s)", lasts, *lasts);
        debug("Delimiters: %s", delimiters);

    }

    /*  Now find the next string portion, starting from current
        position and moving up the string, checking each character
        against the delimiters string.

        If a match is found before the length of the string, find the next
        delimiter, then return that portion of the string.  cur_pos gets
        set to the position of the ending delimiter.

        If no match is found, return the whole string and set cur_pos
        to the size of the string.

        If cur_pos is at the end of the string, return NULL.

     */

    /*  If we are at the end of the string already */

    debug("Lasts first char is: %c", *(*lasts));

    if (*(*lasts) == '\0') {
        debug("lasts is null");
        return NULL;
    }

    for (i = 0; *((*lasts)+i) != '\0'; i++) {

        debug("Checking %c against %s", *((*lasts)+i), delimiters);

        if (strchr(delimiters, *((*lasts) + i)) != NULL) {
            debug("Found delimiter, length is %d", i);
            length = i;
            break;
        }

    }

    /*  If we reached end of string without finding, end of string is
        our substring */

    if ( *((*lasts)+i) == '\0') {
        length = i;
    }

    /*  Now check end and pull out string */

    debug("Start is %x, end is %x: ", *lasts, (*lasts)+length);

    tok = (char *) calloc((length + 1), sizeof(char));

    if (tok == NULL) {
        perror("Calloc tok array failed");
        return NULL;
    }

    /*  Copy string over */

    for (i = 0; i < length && *(*lasts) != '\0'; i++) {

        *(tok+i) = *(*lasts);

        (*lasts)++;

        debug(">%c<", *(tok+i));

    }

    (*lasts)++;

    *(tok + i + 1) = '\0';

    debug("This token (from %s): >>%s<<", *lasts, tok);

    /*  If NOTOKENS is on, skip consecutive delimiters */

    if (flags == NOTOKENS) {
        debug("No tokens is on");
        while (strchr(delimiters, *(*lasts)) != NULL) {
            debug("Found %c at %x", *(*lasts), *lasts);

            (*lasts)++;

            if (*(*lasts) == '\0') {
                break;
            }

        }
    }

    debug("Exiting estrtok function, lasts now points at %c", *(*lasts));

    return tok;

}

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/