3

The code is attempting to serialize a large uint8_t array into a binary character stream. I should have plenty of room in the buffer to copy this data; why am I getting these errors? Posted is a complete runnable code with the output error. The valgrind command used is:

valgrind --leak-check=yes --track-origins=yes ./prog

Main:

#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdint.h"
#include <unistd.h>

#define MAX_FRAME_SIZE 9236
#define DAT_LEN 8202

void create_bit_stream(uint8_t frame[], size_t frame_size, char *frame_bits)
{
  /*
   * Takes in uint8_t array of data and converts to binary stream of characters
   * frame        : input array of uint8_t type data
   * frame_size   : size_t length of frame --> sizeof(frame)/sizeof(frame[0])
   * frame_bits   : pointer for returning the character string
   *
   * RETURNS string of binary values generated from input array
  */

  uint8_t tmp[frame_size];
  memset(tmp,0,frame_size);
  memcpy(tmp,frame,frame_size);
  // char bit_string[frame_size*8+1];
  char *bit_string = malloc(frame_size*8+1);
  memset(bit_string,'\0',frame_size*8 + 1);
  for (int i = 0; i < frame_size; i++)
  {
    for (int j = 0; j < 8; j++)
    {
      bit_string[i*8+j] = '0' + (tmp[i] >> 7);
      tmp[i] <<= 1;
    }
  }
  bit_string[frame_size*8] = '\0';
  strcpy(frame_bits, bit_string);
  free(bit_string);
  return;

}

int main(int argc, char *argv[])
{

 char *frame_bits = malloc(MAX_FRAME_SIZE + 1);
 if(!frame_bits)
 {exit(EXIT_FAILURE);}
 memset(frame_bits,'\0',MAX_FRAME_SIZE + 1);

 uint8_t *DAT_frame = malloc(DAT_LEN);
 if(!DAT_frame)
 {exit(EXIT_FAILURE);}
 memset(DAT_frame,0,DAT_LEN);

 //fill with arbitrary data
 for(int i = 0; i < DAT_LEN; i++)
 {
   DAT_frame[i] = i % 255;
 }

 create_bit_stream(DAT_frame, DAT_LEN, frame_bits);

 free(frame_bits); free(DAT_frame);
 return 0;
}

Error:

==2994== Invalid write of size 1
==2994==    at 0x4C31060: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2994==    by 0x40088B: create_bit_stream (stack.c:36)
==2994==    by 0x400993: main (stack.c:61)
==2994==  Address 0x5205455 is 0 bytes after a block of size 9,237 alloc'd
==2994==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2994==    by 0x4008CE: main (stack.c:45)
==2994== 
==2994== Source and destination overlap in strcpy(0x5203040, 0x52074f0)
==2994==    at 0x4C310E6: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2994==    by 0x40088B: create_bit_stream (stack.c:36)
==2994==    by 0x400993: main (stack.c:61)
gutelfuldead
  • 562
  • 4
  • 22
  • 2
    This isn't your problem, but FYI, `sizeof(char)` is 1 **by definition**, thus `foo * sizeof(char)` is redundant and a bad code smell. – zwol Feb 02 '17 at 21:08
  • you're gonna have to cut this down there's too much noise in the question – Ryan Haining Feb 02 '17 at 21:09
  • @RyanHaining not sure what you would have me remove. There are two pointer initializations and a very small function. There is literally nothing extraneous here. – gutelfuldead Feb 02 '17 at 21:12
  • Further explanation: you might not think `sizeof(uint8_t)` was the same thing as `sizeof(char)`, but it has to be, because `char` cannot be _smaller_ than `uint8_t` (`CHAR_BIT >= 8` is required), and if it is _bigger_ (i.e. `CHAR_BIT > 8`), then the implementation is required to _not provide `uint8_t`_. – zwol Feb 02 '17 at 21:14
  • 3
    I can reproduce the problem (after putting back in the `#include`s and the top-level file structure -- please don't make people do that in the future, provide a [minimal but *complete* example](https://stackoverflow.com/help/mcve)) and am investigating. – zwol Feb 02 '17 at 21:16
  • Thank you @zwol for the advice; I will post accordingly in the future. Are you saying that I should not be using `sizeof(uint8_t)` as well; I'm not sure I understood your point there. – gutelfuldead Feb 02 '17 at 21:24
  • *Are you saying that I should not be using `sizeof(uint8_t)`* -- Yes. The standard guarantees that either `sizeof(uint8_t) == 1` or `uint8_t` does not exist, and the odds of encountering an implementation where `uint8_t` does not exist are vanishingly small (unless you take a notion to port your code to the [PDP-10](http://www.inwap.com/pdp10/)). – zwol Feb 02 '17 at 21:29
  • Re "*I will post accordingly in the future*", It's not too late. Please provide a runnable demonstration – ikegami Feb 02 '17 at 21:37
  • @ikegami updated. – gutelfuldead Feb 02 '17 at 21:53

1 Answers1

3

Your create_bit_stream takes a stream of bytes and expands it to a stream of ASCII-coded bits. That is, if you feed it byte 0x42 ('B') it will produce the string "01000010", which is nine bytes long (counting the terminating nul). You forgot to take this into account when you allocated space for frame_bits -- not in create_bit_stream, but in main:

char *frame_bits = (char *)malloc((MAX_FRAME_SIZE + 1)*sizeof(char));

should read

char *frame_bits = malloc(MAX_FRAME_SIZE * 8 + 1);

(Don't cast the result of malloc.)

(As I pointed out in the comments on the question, sizeof(char) == 1 and sizeof(uint8_t) == 1 by definition; explicitly writing either is redundant and a bad code smell.)

(APIs like these, where the caller supplies a variable-length buffer that the callee writes into, should always pass in the size of the output buffer. Your design is dangerous for the same reason that gets and sprintf are dangerous.)

zwol
  • 135,547
  • 38
  • 252
  • 361
  • using this correction valgrind still complains of `Invalid write of size 1` in the `strcpy` function. edit: I am using `valgrind --leak-check=yes --track-origins=yes ./program` – gutelfuldead Feb 02 '17 at 21:34
  • 1
    @gutelfuldead After making the above change I get no further complaints from `valgrind`. The remaining problem is probably in the part of your code that I had to reconstruct. Please edit your question and supply the _complete_ source code to your test program. – zwol Feb 02 '17 at 21:38
  • you are correct. I'm not sure where the issue was coming from; I refactored it into a single source and it worked. Thanks. – gutelfuldead Feb 02 '17 at 21:44