Thread: Repeated calls to realloc causes segfault

  1. #1
    Registered User
    Join Date
    Mar 2009
    Posts
    399

    Repeated calls to realloc causes segfault

    Repeated calls to bitstream_add_bit will eventually cause a segfault. A backtrace revealed that it was realloc that crashed. I've looked at the most common mistakes involving realloc but I can't find the source of this bug. I added some exit calls just to force an exit on error but that's not happening either.

    bitstream.c
    Code:
    #include <errno.h>
    #include <limits.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    
    #include "bitstream.h"
    
    void bitstream_init(Bitstream *stream)
    {
        if (stream)
        {
            stream->base = NULL;
            stream->byte_count = 0;
            stream->bit_count = 0;
            stream->read_byte_offset = 0;
            stream->read_bit_offset = 0;
        }
    }
    
    void bitstream_rewind(Bitstream *stream)
    {
        if (stream)
        {
            stream->read_byte_offset = 0;
            stream->read_bit_offset = 0;
        }
    }
    
    int bitstream_is_empty(const Bitstream *stream)
    {
        if (!stream)
        {
            return 1;
        }
        
        return (!stream->base || (stream->byte_count == 0 && stream->bit_count == 0));
    }
    
    void bitstream_clear(Bitstream *stream)
    {
        if (stream)
        {
            free(stream->base);
            stream->base = NULL;
            stream->byte_count = 0;
            stream->bit_count = 0;
            stream->read_byte_offset = 0;
            stream->read_bit_offset = 0;
        }
    }
    
    int bitstream_add_bit(Bitstream *stream, const unsigned char bit)
    {
        unsigned char *current;
        int num_bits_available;
        
        if (!stream)
        {
            return 0;
        }
        
        if (bitstream_is_empty(stream))
        {
            errno = 0;
            stream->base = malloc(1);
            if (!stream->base || errno != 0)
            {
                perror("malloc");
                exit(1);
                return 0;
            }
            *stream->base = 0;
        }
        
        current = stream->base + stream->byte_count;
        num_bits_available = CHAR_BIT - stream->bit_count;
        if (num_bits_available == 0)
        {
            if (stream->byte_count == LONG_MAX)
            {
                fprintf(stderr, "Error: Bitstream is full.");
                exit(1);
                return 0;
            }
            
            if ((size_t)-1 < LONG_MAX)
            {
                fprintf(stderr, "Error: SIZE_MAX < LONG_MAX");
                return 0;
            }
            
            errno = 0;
            current = realloc(stream->base, stream->byte_count + 1);
            if (!current || errno != 0)
            {
                perror("realloc");
                exit(1);
                return 0;
            }
            stream->base = current;
            stream->byte_count += 1;
            stream->bit_count = 0;
            current = stream->base + stream->byte_count;
            *current = 0;
            num_bits_available = CHAR_BIT;
        }
        
        *current = (bit << (num_bits_available - 1)) | *current;
        stream->bit_count += 1;
        return 1;
    }
    bitstream.h:
    Code:
    #ifndef BITSTREAM_H
    #define BITSTREAM_H
    
    #include <stdio.h>
    
    typedef struct Bitstream
    {
        unsigned char *base;
        long int byte_count;
        int bit_count;
        long int read_byte_offset;
        int read_bit_offset;
    } Bitstream;
    
    void bitstream_init(Bitstream *stream);
    void bitstream_rewind(Bitstream *stream);
    int bitstream_is_empty(const Bitstream *stream);
    void bitstream_clear(Bitstream *stream);
    Bitstream *bitstream_copy(const Bitstream *stream);
    int bitstream_add_bit(Bitstream *stream, const unsigned char bit);
    int bitstream_add_stream(Bitstream *dest, Bitstream *src);
    void bitstream_print(const Bitstream *stream);
    int bitstream_read_bit(Bitstream *stream, unsigned char *result);
    int bitstream_write_to_file(Bitstream *stream, FILE *output);
    
    #endif
    Test file:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #include "bitstream.h"
    
    int main(void)
    {
        Bitstream stream1;
        int i;
        
        bitstream_init(&stream1);
        for (i = 0; i < 10000000; ++i)
        {
            if (!bitstream_add_bit(&stream1, 1))
            {
                puts("Error adding bit.");
                return EXIT_FAILURE;
            }
        }
    
        bitstream_clear(&stream1);
        return EXIT_SUCCESS;
    }

  2. #2
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,731
    I'm not sure, but I noticed that you change the base. At another call, you call "realloc()" with that new base. Calling "realloc()" or "free()" with not the initial base address ( the one returned by malloc or realloc ) you invite undefined( implementation-defined? ) behaviour.

    EDIT: Never mind, I was wrong...
    Last edited by GReaper; 02-20-2012 at 06:55 PM.
    Devoted my life to programming...

  3. #3
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,731
    I tested your code a bit, but there seems to be no mistake anywhere! The segfault was coming from inside realloc as you said. I don't know what the problem is, but I managed to stop the segfault by allocating an additional byte:
    Code:
    current = realloc(stream->base, stream->byte_count + 2);
    Devoted my life to programming...

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,170
    > current = realloc(stream->base, stream->byte_count + 1);
    On the first time through here, stream->byte_count is still 0, so you end up reallocing just 1 byte (but you already have one).

    As GReaper points out, you're off by 1.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Repeated calls to sscanf
    By jcarellanov in forum C Programming
    Replies: 10
    Last Post: 08-18-2011, 06:53 AM
  2. Why does realloc cause a segfault here?
    By Boxknife in forum C Programming
    Replies: 3
    Last Post: 05-06-2009, 10:54 PM
  3. repeated random
    By xdeath in forum C++ Programming
    Replies: 5
    Last Post: 04-10-2003, 03:52 PM
  4. segfault on realloc
    By ziel in forum C Programming
    Replies: 5
    Last Post: 03-16-2003, 04:40 PM
  5. repeated value in file
    By lockpatrick in forum C Programming
    Replies: 3
    Last Post: 05-11-2002, 11:57 PM