2

I'm writing a "Who want's to be a millionaire" game in C, with SDL included. I have developed the SDL graphics and separately the data processing. The latter is the one, I'm having problems with.

It gets a roughly 5000 lines long .csv file, and puts the details into structures with the help of dynamically allocated memories. Then it gets printed into the console. However, it only works every 3rd time or so. Other times, the program freezes. Tried debugging, it said:

Program received signal SIGTRAP, Trace/breakpoint trap.

Think I narrowed down the problem to this part:

while ((read = getline(&line, &n, kerdes)) != -1) {
    sp = p = line;
    field = 0;
    // The below line triggers the signal
    questions[cnt] = (Question*) malloc(sizeof(Question));

    // Cuts
    while (*p != '\0') {
        if (*p == ',') {
            *p = 0;

            if (field == 0) questions[cnt]->nth = atoi(sp);
            if (field == 1) questions[cnt]->question_to = strdup(sp);
            if (field == 2) questions[cnt]->answer_a = strdup(sp);
            if (field == 3) questions[cnt]->answer_b = strdup(sp);
            if (field == 4) questions[cnt]->answer_c = strdup(sp);
            if (field == 5) questions[cnt]->answer_d = strdup(sp);
            if (field == 6) questions[cnt]->answer_r = strdup(sp);
            if (field == 7) questions[cnt]->cat = strdup(sp);

            *p = ',';
            sp = p + 1;
            field++;
        }
        p++;
    }
    cnt++;
}

The getline function is the one from this answer:

size_t getline(char **lineptr, size_t *n, FILE *stream) {
    char *bufptr = NULL;
    char *p = bufptr;
    size_t size;
    int c;

    if (lineptr == NULL) {
        return -1;
    }
    if (stream == NULL) {
        return -1;
    }
    if (n == NULL) {
        return -1;
    }
    bufptr = *lineptr;
    size = *n;

    c = fgetc(stream);
    if (c == EOF) {
        return -1;
    }
    if (bufptr == NULL) {
        bufptr = malloc(128);
        if (bufptr == NULL) {
            return -1;
        }
        size = 128;
    }
    p = bufptr;
    while(c != EOF) {
        if ((p - bufptr) > (size - 1)) {
            size = size + 128;
            bufptr = realloc(bufptr, size);
            if (bufptr == NULL) {
                return -1;
            }
        }
        *p++ = c;
        if (c == '\n') {
            break;
        }
        c = fgetc(stream);
    }

    *p++ = '\0';
    *lineptr = bufptr;
    *n = size;

    return p - bufptr - 1;
}

I did - hopefully - searched stackoverflow thoroughly enough, without any success.

What could cause the problem?
Overindexing is not behind it in my opinion and free() is used well.

Please find the whole .c file on pastebin, following this link: Click here

CSV file (non-english) is accessible using the following link: Click here

Ben V
  • 23
  • 5

1 Answers1

0

The problem is in getline code, that is very b0rken. I replaced it with the POSIX standard getline and it works flawlessly. The problem is the realloc code here:

p = bufptr;
while(c != EOF) {
    if ((p - bufptr) > (size - 1)) {
        size = size + 128;
        bufptr = realloc(bufptr, size);
        if (bufptr == NULL) {
            return -1;
        }
    }
    *p++ = c;
    if (c == '\n') {
        break;
    }
    c = fgetc(stream);
}

The realloc can (and most probably will) return a pointer to a new buffer, but the p will point to the old buffer, therefore the line *p++ = c; will have undefined behaviour.

I have now provided a (hopefully) fixed version of that getline implementation in my answer to the getline question.

  • Thank you for pointing that out and I highly appreciate your dedication! However, I'm unable to use the `getline()` as it's not included in my stdio.h. "undefined reference to getline" – Ben V Nov 10 '17 at 18:18
  • No commands, Win10 and Code::Blocks (16.0.1) is the requirement. There were some known compatibility issues from the beginning, but fixes have been provided. – Ben V Nov 10 '17 at 18:23