HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

Read until EOF and realloc as needed

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
neededuntilreadeofreallocand

Problem

This is a function that reads until EOF and reallocs as it goes.

char *
read_to_end(int fd, int *bread)
{
    ssize_t size, nread, rc;
    char *buf, *tmp;

    nread = 0;
    size = MINLEN;
    buf = malloc(size);

    while ((rc = read(fd, buf + nread, size - nread))) {
        if (rc < 0) {
            if (errno == EINTR)
                continue;

            goto error;
        }

        nread += rc;

        /* See if we need to expand. */
        if (size - nread < MINLEN) {
            size *= 2;

            /* Make sure realloc doesn't fail. */
            if (!(tmp = realloc(buf, size)))
                goto error;

            buf = tmp;
        }
    }

    /* Shrink if necessary. */
    if (size != nread && !(tmp = realloc(buf, nread)))
        goto error;

    buf = tmp;
    *bread = nread;
    return buf;

error:
    free(buf);
    return NULL;
}


Do you have any improvement suggestions?

Solution

Seeing this is 'unanswered' here's my tuppence worth:

If you are reading a file I suggest you get the file size first, eg using fstat(), allocate a buffer of the correct size and read into that.

Alternatively, if the file is big and you have OS support, consider mapping the file into memory using mmap(). This maps the file into virtual memory but does not read it immediately. As you access the memory into which the file is mapped the file is read into that address space for you (in the background) by the OS.

On your code, I have a few comments:

-
If you have a stderr, perhaps add a call to perror() on error.

-
It looks as if you always re-alloc, even if the initial buffer is big enough.

-
If zero bytes are read, you will realloc(buf, 0). realloc man page says this is ok.

-
Add a bracket around size != nread - I always have to check operator precedence in statements like this and I guess I am not alone. Brackets save the reader the trouble.

-
I would prefer *bread to be set to 0 on failure. Should bread be size_t ?

Context

StackExchange Code Review Q#9421, answer score: 3

Revisions (0)

No revisions yet.