segment fault after parsing unsigned char to int pointer - c

I'm facing a problem when trying to read a binary file of fixed size. The code below returns segmentation Fault just before closing the file. What I want to achieve it is to return an int pointer back to the main function.
The file it s a raw grayscale image, which has values from 0 to 255, that's why I'm using unsigned char.
How can I convert and assign from unsigned char to *int properly?
Any kind of help will be welcome!
void readBinaryFile(char *filename, int *in){
FILE *file;
long length;
unsigned char *imagen;
int c;
file = fopen(filename, "rb");
fseek(file,0,SEEK_END);
length = ftell(file);
imagen = (unsigned char *) malloc(length);
fseek(file, 0, SEEK_SET);
fread(imagen, length, 1 , file);
int cont;
//c+4: file contains values from 0 to 255
for(c=0,cont=0;c<length;c=c+4,cont++){
in[cont] = (unsigned char) imagen[c];
}
for(cont=0;cont<length/4;cont++){
printf("%d",(int) in[cont]);
}
fclose(archivo);
free(imagen_buffer);
}
void main(int argc, char **argv){
int *in;
int fixed_size = 784;
in = (int *) malloc((fixed_size)*(fixed_size));
readBinaryFile("test.raw", in);
int c;
for(c=0;c<((fixed_size)*(fixed_size));c++){
printf("%d", (unsigned char) in[c]);
}
}

This
int *in;
makes in point to an int.
This
in = (int *) malloc((fixed_size)*(fixed_size));
allocates to in 784*784=614656 bytes.
You need 784*784 ints.
An int needs sizeof (int) bytes, which by definition is very well might be and most often is larger then 1.
From 1. and 2. above it can be deduces that 784*784 int needs more then 784*784 bytes.
So change
in = (int *) malloc((fixed_size)*(fixed_size));
to be
in = (int *) malloc((fixed_size)*(fixed_size) * sizeof (int));
or even nicer and safer with less noise do
in = malloc(fixed_size*fixed_size * sizeof *in);
because
in C there is no need to cast void* (which malloc() returns).
the parentheses around fixed_size are useless.
using sizeof *in returns the same as sizeof (int), but would "survive" if you changed int * in to become for example unsigned * in.
Also while reading you need to make sure to not read more then 784*784 char, as else the memory allocated for the int will be overflowed, which in turn invoked the infamous Undefined Behaviour.

Related

confusion about printf() in C

I'm trying to hexdump a file with following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define SIZE 16
void pre_process(char buffer[],int len);
int main(int argc, char **argv){
if(argc == 2){
char *file = argv[1];
FILE *input = fopen(file,"r");
char buffer[SIZE];
char *tmp = malloc(4);
while(!feof(input)){
printf("%06X ",ftell(input)); /*print file pos*/
fread(buffer,1,SIZE,input); /*read 16 bytes with buffer*/
for (int i=0;i<SIZE;i += 4){ /*print each 4 bytes with hex in buffer*/
memcpy(tmp,buffer+i,4);
printf("%08X ",tmp);
}
printf("*");
pre_process(buffer,SIZE); /*print origin plain-text in buffer. subsitute unprint char with '*' */
printf("%s",buffer);
printf("*\n");
}
free(tmp);
fclose(input);
}
}
void pre_process(char buffer[],int len){
for (int i=0;i<len;i++){
if(isblank(buffer[i]) || !isprint(buffer[i]))
buffer[i] = '*';
}
}
reading a slice from lord of ring,result as below:
enter image description here
so, why the hex code are all the same ? It looks like something wrong with printf("%08X ",tmp);
thx for your help.
The answer lies here:
memcpy(tmp,buffer+i,4);
printf("%08X ",tmp);
memcpy as you might already be aware, copies 4 bytes from buffer+i to where tmp is pointing to.
Even though this is done in a loop, tmp continues to hold the address of a specific location, which is never changed. The contents at that address/location in memory are updated with every memcpy() call.
In a nutshell, the house remains there only, hence the address remains the same but people change places, new people arrive as older ones are wiped out!
Also, there is plenty to improve/fix here. I recommend starting with enabling warnings by -Wall option with your compiler.
tmp stores the address of a buffer; that address never changes. What you want to print is the contents of the buffer that tmp points to. In this case, tmp point to a buffer of 4 chars; if you write
printf( "%08X ", *tmp );
you’ll only print the value of the first element - since tmp has type char *, the expression *tmp has type char and is equivalent to writing tmp[0].
To treat what’s in those bytes as an unsigned int (which is what the %X conversion specifier expects), you need to cast the pointer to the correct type before dereferencing it:
printf( "%08X ", *(unsigned int *) tmp );
We first have to cast tmp from char * to unsigned int *, then dereference the result to get the unsigned int equivalent of those four bytes.
This assumes sizeof (unsigned int) == 4 on your system - to be safe, you should write your malloc call as
char *tmp = malloc( sizeof (unsigned int) );
and
for ( int i = 0; i < SIZE; i += sizeof (unsigned int) )
{
memcpy( tmp, buffer + i, sizeof (unsigned int) );
...
}
instead.
You should not use feof as your loop condition - it won’t return true until after you try to read past the end of the file, so your loop will execute once too often. You’ll want to look at the return value of fread to determine whether you’ve reached the end of the file.

reading a big bin-file(~2mb) in c

I want to read a bin-file with a size under 2mb.
At the moment my code for reading the bin file looks like this:
edit:
#define MAX_BYTES_IN_FILE 500000 // ~ 2mb
#define ERROR_FILE 1
int get_byte_from_file(FILE *stream, unsigned char *dataarray) {
int counter = 0;
while ((dataarray[counter] = fgetc(stream)) != EOF) {
counter += 1;
}
return counter;
}
Main looks like this for the example use of the function.
int main(int argc, char **argv) {
FILE *datei;
unsigned int number_of_bytes;
unsigned char *dataarray;
dataarray = (unsigned char *)malloc(sizeof(unsigned char) * MAX_BYTES_IN_FILE);
datei = fopen(argv[1], "rb");
number_of_bytes = get_byte_from_file(datei, dataarray);
for (int i = 0; i < number_of_bytes; i++)
printf("%x ", dataarray[i]);
return 0;
}
Maybe I did a simple mistake but cant see it the error is still: Segmentation fault (core dumped)
This line is sufficient to crash your program:
while ((dataarray[counter] = fgetc(stream)) != EOF) {
Let's go through it step by step:
fgetc(stream) reads a byte and returns its value or EOF. Because a byte can have any possible value, fgetc() returns a larger int, which can hold an EOF value that is distinct from any byte value that might be found in the file.
You assign this int value to an unsigned char. An EOF value will be truncated to this datatype.
The value of the assignment is of type unsigned char, and the converted EOF value is not equal to EOF anymore. Thus, the comparison always fails, and your program keeps fetching data until the buffer overruns and nasty things begin to happen.
You need to store the result of fgetc() in an int variable until you've checked that it is indeed not the EOF value.
Maybe something like this.
void *readfile(FILE *fi, long *filesize)
{
void *buff;
fseek(fi, 0, SEEK_END);
*filesize = ftell(fi);
fseek(fi, 0, SEEK_SET);
buff = malloc(*filesize);
if(buff)
{
fread(buff, 1, *filesize, fi);
}
return buff;
}
You need to add error checks- I did not as it is only the idea.
And your usage:
int main(int argc, char **argv) {
FILE *datei;
long number_of_bytes;
unsigned char *dataarray;
datei=fopen(argv[1],"rb");
dataarray = readfile(datei, &number_of_bytes);
for (int i=0;dataarray && i<number_of_bytes;i++)
printf("%hhx ",dataarray[i]);
return 0;
}
The reason you get a segmentation fault is your allocation is incorrect: you allocate MAX_BYTES_IN_FILE bytes instead of unsigned int elements. As allocated, the array has only MAX_BYTES_IN_FILE / sizeof(unsigned int) elements, whereas the file is probably MAX_BYTES_IN_FILE * sizeof(unsigned int) bytes long.
You are reading bytes from the file (values between 0 and 255) but you use unsigned int elements. What is the logic? Does the file contain 32-bit values or individual bytes?
Once you can confirm that the file contents is exactly the same as the representation of the array in memory, you can use fread() to read the whole file in a single call.

How to read from pipe into a file?

I would like to read from the pipe straight into a file with the code below. base_fd is a pipe.
FILE* fp = fopen("dec_data", "wb+");
int r_result;
int len = msg_length-part-3; //set to 75933
while ((r_result = read(base_fd[0], fp, len))) {
printf("r_result: %d \n", r_result);
len -= r_result;
}
The read seems to happen fine, with r_result showing 65536 and then 10397 as required. However, when I inspect the file I created, it has a size of 0 bytes...
You have a semantic error in your code.
Take a look at the read(2) system call signature:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
The second parameter to the function is a void pointer (void *buf), which is where read will store the count bytes it reads from fd descriptor.
However, a FILE * is an abstraction of the C library. In this answer you can see more of it. The struct FILE in MinGW32 5.1.4 is:
typedef struct _iobuf
{
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
} FILE;
What read will do is similar to how we copy strings. Consider this function:
void strcpy(char *dst, char *src)
{
while(*src) *dst++ = *src++;
}
This function will copy the contents from src into dst until it finds a NULL terminating byte. This is obviously a very flawed function and should never be used, but illustrates why your example doesn't work.
Under the hood, what read is doing is very similar to this strcpy function: it is overwriting a lot of bytes in memory starting at the address pointed to by the fp pointer. You are effectively losing your reference to the FILE * pointer and the resources associated to it.
I'll bet that if you try to close(fp) after that loop you'll get a segmentation fault (it's Undefined Behavior, but I'll bet anyway).
The right way to do what you want is:
FILE* fp = fopen("dec_data", "wb+");
char *buf;
int r_result;
int len = msg_length - part - 3; //set to 75933
buf = malloc(len);
if(!buf) {
perror("malloc");
exit(EXIT_FAILURE);
}
while ((r_result = read(base_fd[0], buf, len))) {
fprintf(fp, buf);
len -= r_result;
}
free(buf);
close(fp); // now it closes the file pointer

Bus error. Cannot access memory

I'm getting bus error.
While debugging the snippet below and stepping to the end of writeDmpFile I'm getting:
writeDmpFile (tree=0x56a310, filename=0x7fffffffd450 "20140318.221058") at unzipper_m1.c:146
146 }
(gdb) n
Cannot access memory at address 0x38353031323236
The file is written though, but program ends with bus error.
Here the code:
typedef struct dmpParams_t
{
char buff[6000000];
size_t *size;
}dmpParams_t;
int writeFile(char *name, unsigned char *buff, size_t *size,const char *dir )
{
FILE * pFile;
chdir (dir);
pFile = fopen ( name, "wb");
fwrite (buff , sizeof(unsigned char), *size, pFile);
fclose (pFile);
return 1;
}
int writeDmpFile(GTree *tree, char *filename)
{
char dmpfilename[32];
dmpfilename[0] ='\0';
dmpParams_t params;
params.buff[0] ='\0';
size_t size =0;
params.size=&size ;
g_tree_foreach(tree, (GTraverseFunc)writeDmpFileLine, &params);
sprintf (dmpfilename, "InstrumentList_FULL.csv_%.*s", 15, filename);
writeFile(dmpfilename, ( unsigned char *)params.buff, &size , dmpdir);//(size_t *)params.size, dmpdir);
}
It looks like a buffer overrun of dmpfilename. You allocated an array of length 32. You then format it with "InstrumentList_FULL.csv_%.*s". That's 24 characters, plus 15 for the filename, plus a null terminator. That's more than 32.
Increase the size of the buffer.
Oh, and dmpParams_t is, er, rather large. Perhaps there's a stack overflow when you allocate one of those as a local.
Some other comments:
You could usefully use const a bit more.
Declaring size as size_t* in the struct is a bit odd. You pass the address of the struct to g_tree_foreach. I'd declare size as size_t and let g_tree_foreach modify the value.
Likewise, it seems odd that you pass the address of size to writeFile. Again a const value seems to make more sense.

C -Struct array, problems with free, problems with assigning values in my struct array

What follows is my program. I'm creating a struct, using malloc to allocate memory because I want a very large struct array, and then passing that struct array to functions. The functions aren't important, because I can't get out of the main program. My confusion is my compiler (gcc) saying that each_event is undeclared when I try to free it, but nowhere else. When I comment out the free statement it compiles, but then valgrind says I have an invalid write of size 4 when I do the each_event[i].timestamp = tim[i] line. The line above that is commented out because valgrind was telling me the error was there (I compiled with gcc -g -O0) even though I knew it had to mean the line below.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define event_length 512
#define bits_n_byte 8
#define timestamp_bytes 8
typedef enum type {
DATA, CLOCK, EXPECTED, SPILL, ALL
} type;
typedef struct event {
char clocbuffer[event_length*bits_n_byte];
char datbuffer[event_length*bits_n_byte];
char expect[event_length];
char spil[event_length];
char clocerror[event_length*bits_n_byte];
char daterror[event_length*bits_n_byte];
long unsigned int timestamp;
} event;
int i, j, k, l, length, nevents;
char **spil, **expect, **dat, **cloc, **clocerror, **daterror;
long unsigned int *tim;
char library[256];
char *runnum, *clocmode, *datmode;
void GetPiece(char*, type, struct event*);
void FindMode(type);
void ErrorPiece(type);
int main(int argc,char **argv) {
if (argc != 2) {fprintf(stderr, "Format: ./program #_patterns\nTry again.\n");}
for (i=0;i<256;i++) library[i]=i;
FILE *IN = NULL;
char *buffer = NULL;
runnum = (char *) malloc(2);
runnum = strncpy(runnum,argv[1],1);
runnum[1] = '\0';
IN=fopen(argv[1], "r"); /*Open input file.*/
if (IN)
{
fseek(IN, 0, SEEK_END); /*This finds */
length = ftell(IN); /*the length */
fseek(IN, 0, SEEK_SET); /*of the file.*/
buffer = malloc(length + 2); /*for buffer. */
fread(buffer, 1, length, IN);
tim = (long unsigned int *) malloc(length + 2*sizeof(long unsigned int));
fread(tim, sizeof(long unsigned int), length/sizeof(long unsigned int), IN);
fclose(IN);
nevents = length/2056;
struct event* each_event = (struct event *) malloc(nevents*sizeof(struct event));
for (i=0; i<length/sizeof(unsigned long int); i+=2056/sizeof(unsigned long int))
{
tim[i] = __builtin_bswap32 (tim[i]);
tim[i]-=0x80000000;
//if (tim[i]<1200000000 || tim[i]>1300000000) fprintf(stderr, "Check timestamp. Either endianness, size of bytes, or size of long ints are different.");
each_event[i].timestamp = tim[i];
}
clocmode = malloc(nevents);
datmode = malloc(nevents);
GetPiece(buffer, DATA, each_event);
GetPiece(buffer, CLOCK, each_event);
GetPiece(buffer, EXPECTED, each_event);
GetPiece(buffer, SPILL, each_event);
GetPiece(buffer, ALL, each_event);
FindMode(DATA);
FindMode(CLOCK);
ErrorPiece(DATA);
ErrorPiece(CLOCK);
}
else fprintf(stderr,"Error in file naming/opening.\n"); /*error*/
free (buffer);
free (tim);
free (runnum);
free (clocmode);
free (datmode);
free (each_event);
return 0;}
Because each_event is declared inside the if { ... } block, it is out of scope by the time you try to free() it. Either free it at the end of the if { ... }, or put the declaration in along with the others at the start of main(). If you do the latter, though, you will probably get warnings about it possibly being used without being initialized, so the first option is probably best.

Resources