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;
}