#ferror problem

33 messages · Page 1 of 1 (latest)

solemn vessel
#
ErrorCode readFile(char *fileName, char **fileContent, size_t *size) {
    FILE *f = fopen(fileName, "r");
    if (!f) {
        fprintf(stderr, "Error opening file %s\n", fileName);
        return READ_FILE_OPEN_ERROR;
    }

    char *buffer = malloc(CHUNK_SIZE);
    if (!buffer) {
        fprintf(stderr, "malloc failure\n");
        return READ_FILE_MALLOC_FAILURE;
    }
    size_t bufferSize = CHUNK_SIZE;
    size_t bytesRead;
    size_t i = 0;

    while ((bytesRead = fread(buffer + i, 1, CHUNK_SIZE, f))) {
        i += bytesRead;
        if (bytesRead == CHUNK_SIZE) {
            char *temp = realloc(buffer, bufferSize += bytesRead);
            if (!temp) {
                fprintf(stderr, "realloc failure\n");
                free(buffer);
                return READ_FILE_REALLOC_FAILURE;
            }
            buffer = temp;
        }
    }

    char *temp = realloc(buffer, i + 1);
    if (!temp) {
        fprintf(stderr, "realloc failure\n");
        free(buffer);
        return READ_FILE_REALLOC_FAILURE;
    }
    buffer = temp;
    buffer[i] = '\0';
    bufferSize = i + 1;

    if (ferror(f)) {
        fprintf(stderr, "Error reading file %s: %s\n", fileName, strerror(errno));
        free(buffer);
        fclose(f);
        return READ_FILE_READ_ERROR;
    }

    *fileContent = buffer;
    *size = bufferSize;
    fclose(f);
    return READ_FILE_SUCCESS;
}

this is the relevant section. the function worked for a small test file. now i wanted to test it with a bigger file and suddenly i got an error. when i run the file normally i get my "Error reading file testfile.txt: Invalid argument" print which i do in the code. but when i run it in the debugger (lldb) and set a breakpoint in the if that checks ferror, the breakpoint does not trigger, i just get an other exception because the string is NULL because the if (ferror(f)) block frees it, but why does it not trigger? Also when i completely delete the if (ferror(f)) block then my code works as intended with no problems, so why is the ferror flag true when there is no error?

dry juncoBOT
#

When your question is answered use !solved or the button below to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

sterile depot
#
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

typedef enum {
    READ_FILE_SUCCESS,
    READ_FILE_OPEN_ERROR,
    READ_FILE_MALLOC_FAILURE,
    READ_FILE_REALLOC_FAILURE,
    READ_FILE_READ_ERROR,
} ErrorCode;

#define CHUNK_SIZE 10

ErrorCode readFile(char *fileName, char **fileContent, size_t *size) {
    FILE *f = fopen(fileName, "r");
    if (!f) {
        fprintf(stderr, "Error opening file %s\n", fileName);
        return READ_FILE_OPEN_ERROR;
    }

    char *buffer = malloc(CHUNK_SIZE);
    if (!buffer) {
        fprintf(stderr, "malloc failure\n");
        return READ_FILE_MALLOC_FAILURE;
    }
    size_t bufferSize = CHUNK_SIZE;
    size_t bytesRead;
    size_t i = 0;

    while ((bytesRead = fread(buffer + i, 1, CHUNK_SIZE, f))) {
        i += bytesRead;
        if (bytesRead == CHUNK_SIZE) {
            char *temp = realloc(buffer, bufferSize += bytesRead);
            if (!temp) {
                fprintf(stderr, "realloc failure\n");
                free(buffer);
                return READ_FILE_REALLOC_FAILURE;
            }
            buffer = temp;
        }
    }

    char *temp = realloc(buffer, i + 1);
    if (!temp) {
        fprintf(stderr, "realloc failure\n");
        free(buffer);
        return READ_FILE_REALLOC_FAILURE;
    }
    buffer = temp;
    buffer[i] = '\0';
    bufferSize = i + 1;

    if (ferror(f)) {
        fprintf(stderr, "Error reading file %s: %s\n", fileName, strerror(errno));
        free(buffer);
        fclose(f);
        return READ_FILE_READ_ERROR;
    }

    *fileContent = buffer;
    *size = bufferSize;
    fclose(f);
    return READ_FILE_SUCCESS;
}

int main(void) {
    size_t size;
    char *fileContent = NULL;
    printf("CODE: %d\n", readFile("./test.c", &fileContent, &size));
    printf("%s\n", fileContent);
    free(fileContent);
    printf("CODE: %d\n", readFile("./test.c", &fileContent, &size));
    printf("%s\n", fileContent);
    free(fileContent);
    return 0;
}

// gcc -g -Og -fsanitize=address,leak,undefined -o test test.c
#

I ran this an couldn't get it to error

#

when I passed an invalid filename it just said not found and exited

#

how big is the file you are trying to read?

#

also there are missing fclose before some of the returns

solemn vessel
#

without the

if (ferror(f)) {
        fprintf(stderr, "Error reading file %s: %s\n", fileName, strerror(errno));
        free(buffer);
        fclose(f);
        return READ_FILE_READ_ERROR;
    }

it works but whit this if somehow ferror is true and errno is set to EINVAL

sterile depot
#

so I generated a 7mb file and ran it with no issues, the only thing I can think of right now is there might be permissions on the file you are trying to read

solemn vessel
#

i tried with administrator cmd.exe but still the error. also when i had less content in the file (just a few words) then i also did not get this error, so i do not think that it is reading permission

sterile depot
#

so I am not fimailar with windows files I used linux for the test and had no issues, so I can't really say what could be going on

drifting fern
#

if the fread return value is lower than CHUNK_SIZE you should already terminate the loop

#

anything lower than the number expected is eof or error, and it seems you try to read again

drifting fern
#

although I don't think that would be a problem, unsure, otherwise usual option of running with the address sanitizer makes sense, especially when you say it is a heisenbug

#

and EINVAL sounds around invalid file handle passed

solemn vessel
drifting fern
#

I don't know if reading after first eof is legal or not - @late gull? as you are online

late gull
drifting fern
#

unless Spectre is using some weird C library, I suspect the error may be in the parts of code never shared

late gull
#

it doesn't same the same for errors, but that's the intent I think

drifting fern
#

tl;dr I was wondering if after his fread() reports short read, another fread() could somehow make ferror() return true

#

because they called fread() once more after short fread()

#

I couldn't reproduce such behavior

#

@solemn vessel btw what is your compiler?

solemn vessel
#

clang

#

with msvcrt

drifting fern
#

well, I don't have any convenient access to Windows and I would probably need to check on the exact same versions of everything you have

#

have you still maybe tried the address sanitizer on the failing version of code (though I've looked few times and things looked okay)

dry juncoBOT
#

@solemn vessel Has your question been resolved? If so, type !solved :)

solemn vessel
drifting fern
#

maybe that's specific to some version of msvc, unfortunately Compiler Explorer doesn't provide such choices

#

I mean msvcrt