I've stumbled upon following problem: I wrote a program in C, which functions as a variation of Mergesort, just with forking. For this problem, I wrote a function which reads exactly one line from some input stream specified by a parameter, adds a '\0' at the end, and returns a boolean, indicating whether a newline character exists or not. The source code is below:
static bool getInputLine(FILE *f, char **input, int *size_in) {
int size = 0;
char todo;
do {
if((*input = realloc(*input, (size + 1) * sizeof(char))) == NULL) exitWithStatus(EXIT_FAILURE, "reallocing FAILED");
todo = fgetc(f);
if(todo == EOF) break;
(*input)[size] = todo;
if(todo == '\n' && size == 0){
fprintf(stdout, "\n");
break;
}
size++;
} while(todo != '\n');
if((*input = realloc(*input, (size+1) * sizeof(char))) == NULL) exitWithStatus(EXIT_FAILURE, "reallocing FAILED");
(*input)[size] = '\0';
*size_in = size;
return size == 0 || todo != '\n';
}
The code works for (almost) any input, at least so I thought. For some reason, if a line is greater than exactly 26 chars, I get:
realloc(): invalid next size Aborted (core dumped)
I'm relatively new to C, and this had me confused as ever. Any help is greatly appreciated, thanks in advance!
My OS is Linux Fedora, if that helps in any way. Should you need anything else, please let me know :)
And just fyi, the input String is malloc'd with sizeof(char) before calling the function! It is freed again at exiting the process.
EDIT: Despite help from various sides, I have not been able to solve this issue. I had to generally rethink my strategy to solve the problem as a whole. I suppose it had something to do with global variables being inherited by the forked child processes, and hence borking the heap structs in some way or another. Unfortunately, I lost track of what happened exactly, despite restructuring my code to make it more debug-friendly.
Thank you very much for your help regardless! :)
Related
After a couple hours working on the recover exercise of cs50 i've been stumbling in the segmentention error problem. After running the debbuger i've discovered that the cause of the segmentation error is the malfuction of fread(memory, 512, 1, file), even after calling the function the memory[] array keeps empty, thus, the segmentation error.
i've tried to work with malloc(512) instead of an unsigned char array but the error persists. Can someone explain why is this happening and how to solve it?
(PS. Sorry for my bad english)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
// making sure the only user input is the name of the file
if (argc != 2)
{
printf("Usage: ./recover image\n");
return 1;
}
// open the file and check if it works
FILE *file = fopen("card.raw", "r");
if (file == NULL)
{
printf("Could not open card.raw.\n");
return 2;
}
int ending = 1000;
int count = 0;
char img = '\0';
FILE *picture = NULL;
unsigned char memory[512];
do
{
//creating buffer and reading the file into the buffer
fread(memory, 512, 1, file);
//checking if the block is a new jpg file
if (memory[0] == 0xff && memory[1] == 0xd8 && memory[2] == 0xff && (memory[3] & 0xf0) == 0xe0)
{
//if it's the first jpg file
if (count == 0)
{
sprintf(&img, "000.jpg");
picture = fopen(&img, "w");
fwrite(&memory, 512, 1, picture);
}
//closing previous jpg file and writing into a new one
else
{
fclose(picture);
img = '\0';
sprintf(&img, "%03i.jpg", count + 1);
picture = fopen(&img, "w");
fwrite(&memory, 512, 1, picture);
}
}
//continue writing into the file
else
{
picture = fopen(&img, "a");
fwrite(&memory, 512, 1, picture);
}
count++;
}
while(ending >= 512);
fclose(file);
fclose(picture);
return 0;
}
if you're using C or C++ then you should be fully aware of the memory model being used. For example, declaring a character local variable, means allocating from 1 to 4 bytes of memory in the stack, depending on memory alignment and architecture being used (16-bit? 32-bit? 64-bit?). And guess what happens when you do sprintf of more than 4 characters on such character local variable. It will overrun to whatever variable occupying the space after the img variable. So you must prepare a buffer large enough to hold characters that are needed to create the filename.
In C, if you make a mistake, there are several possibilities :
sometime you get segmentation fault after you do a mistake
sometime you didn't get any error but the data silently corrupted
sometime error happens long after the mistake is done
There are other problems with your code, which has been pointed out by Weather Vane and Jabberwocky in the comments above. I would like to add that reopening 'img' file and discarding previous file handle is not a good thing either (you already said continue writing? why need to reopen? ). You might get a dangling file handle or needlessly create many file handles during the iteration. C will not help you check such things, it assumes you really know what are you doing. Even mixing types will not cause compile error nor identifiable runtime error. It will just do one of the three things I said above.
You might want to use other modern language with more memory safety features in order to learn programming, like C#, Java or Python.
I've been given this code for an assignment, there supposed to be errors in it but I can't actually figure out what this function is supposed to do, never mind figure out if there's any issues with it...
I am guessing that it's supposed to read the buffer line by line, but I've never seen it done this way before
The buffer that is sent to the function is empty.
int read_line(int sock, char *buffer) {
size_t length = 0;
while (1) {
char data;
int result = recv(sock, &data, 1, 0);
if ((result <= 0) || (data == EOF)){
perror("Connection closed");
exit(1);
}
buffer[length] = data;
length++;
if (length >= 2 && buffer[length-2] == '\r' && buffer[length-1] == '\n') {
buffer[length-2] = '\0';
return length;
}
}
}
Thanks in advance!
I'd say the purpose of this function is to read a line that ends with \r\n from socket stream and store it in a char array as a string, therefore the \0 (string termination character) placement.
Ok, so what's wrong with the code?
I'd start with the input parameter char *buffer - inside the function you do not know its size so you cannot check if it exceeds its size limit and it could lead to buffer overflow.
So it would be better to send buffer length as a parameter and check with every received byte if it can be stored.
EOF - it is defined as -1 and in this case actually doesn't make any sense, because nothing will be setting your data variable to EOF. The only thing you need to look out for is the end of socket stream (recv documentation). And here is an example for EOFusage.
Feel free to remove (data == EOF) from condition.
Let's say you are receiving everything regularly and you receive your last input and connection closes, so you enter this case:
if ((result <= 0) || (data == EOF)){
perror("Connection closed");
exit(1);
}
The problem here is that you won't process your last line and the program will just end. Although, I might be wrong here since I don't know when the connection is getting regularly shut down.
And a minor note here, result that equals to 0 isn't considered as an error, but a regular connection shutdown (or a 0-byte datagram was received).
I hope I haven't missed anything.
I'm writing a function which searches a text file formatted like this:
#User1\pass\
#User2\pass\
#User3\pass\
I have written the function Check_User:
int Check_User(char input[20], FILE *userlist)
{
int c, i;
fseek(userlist, 0, SEEK_SET);
while(1)
{
while((c = fgetc(userlist)) != '#')
{
if(c == EOF)
return 1;
}
while(input[i] == (c = fgetc(userlist)))
{
i++;
}
i = 0;
if(c == '\\')
return 0;
}
}
Which is called from here:
while(Check_User(username, userlist) == 0)
{
printf("Username already in use. Please select another:");
Get_Input(username);
}
Check user checks the file pointed to by *userlist to see if the username[20] contains a username which is already in use. If it is already in use it calls Get_Input for a new username.
The program makes it all the way to the while loop and then gives me a segmentation fault: 11. I have read that this often stems from trying to write beyond the end of an array, or generally doing things to memory you don't have access to. Userlist.txt has been opened in r+ mode.
Thanks for the help.
You did not initialize your variable i before its first use. In C, declared variables are not initialized to numerical 0 (as they would be in C# or Java), but simply use the value that was present at their memory location before. Thus, the value of i may be far bigger that the length of the string input, and input[i] may access an invalid memory location.
As a side note: to quickly debug this yourself under Linux, compile the program with debug symbols (gcc -g) and then use valgrind --tool=memcheck <your program> to let valgrind find the source of error for you.
I am new to C so pardon the simplicity of the question. I am trying to write a function (as a lib, so it must be robust) that constantly reads one byte (EDIT: from a serial port) until a header start byte is encountered. If it finds it, it will read in the rest of the header and payload and store it in a struct. The start of my code looks something like this (some pseudocode will be included):
soh_read = 0;
bytes_read = 0;
bytes_left = 1;
do{
n = read(fd, buf + bytes_read, bytes_left);
if(n < 0){
if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR){
return -1;
}
}else{
bytes_read += n;
if(!soh_read){
if(buf[0] != SOH){
bytes_read = 0;
continue;
}
}
soh_read = 1;
//read header ...
//read payload ...
}while(timeout is not reached);
I assumed I could reset the bytes_read to 0 if SOH is not encountered and try to read in the buf[0] position again, overwriting the garbage it previously read. But it seems like this a case of a buffer overflow and why I am getting a segmentation fault? Why would that not work though? If so, what is the best way to go about this? I wanted to start at buf[0] so it'd be easy to keep track of each of the message fields. Just trying to learn from the experts here, thanks.
You've left out some information crucial to diagnosing the problem with your code as it stands. The single most important thing is (probably) whether your SOH might occur later in the file than you've allowed room for in your buf.
That said, however, I think I'd do things rather differently: since you apparently don't need (or even care about) the data that precedes the SOH anyway, why not just read all that data into one character, overwriting the previous value at each iteration, and only save more than one byte of data after you encounter the SOH so you actually have a use for it.
do {
read(fd, buf, 1);
if (n<0 && errno != EWOULDBLOCK && /* ... */)
return -1;
} while (buf[0] != SOH and !timeout_reached);
// read the header here
I read the input file , which has 911 lines , and want to copy these 911 lines into the output file , after making a few changes to each line..
I am getting segmentation fault when i run this.. I dont know why.. can anyone please help..
#include<stdio.h>
void main()
{
int i;
FILE *fin,*fop;char* str;
fin=fopen("atk561011.txt","r");
if(fin=NULL) printf("ip err");
fop=fopen("svmip.txt","w");
if(fop=NULL) printf("op err");
for(i=1;i<=911;i++)
{
fgets(str,150,fin);
if((i>300&&i<=360)||(i>600&&i<=660))
str[7]='1';
else
str[7]='0';
fputs(str+7,fop);
putc('\n',fop);
}
fclose(fin);
fclose(fop);
}
For a start, this is wrong:
if(fin=NULL)
Should be:
if (fin == NULL)
(the same goes for fop, of course). And if you didn't succeed opening the file - don't just print an error, exit, because what are you going to read from? Keep in mind that the output of printf is buffered and in case of a segfault you won't always see it at all, even if it ran before the fault.
Another thing: you don't allocate memory for str, yet write into it with fgets.
And another thing: reading a pre-defined amount of lines from the file is probably a bad idea. It's better to read from the input until there is an end of file, or until a required amount of lines has been read.
Your not allocating any space for the pointer str.
Change that to either char str[/*Max Length You expect 150? */] or allocate the buffer.
In the meantime your code is walking all over memory - thus the segmentation fault.
Here's the corrected code that should do it.
#include
#define MAX_BUF 150
void main()
{
int i;
FILE *fin,*fop;char* str;
str = malloc((MAX_BUF * sizeof(char)) + 1);
if (str == NULL){
printf("Out of memory\n");
exit(-1);
}
fin=fopen("atk561011.txt","r");
if(fin == NULL){
printf("ip err");
exit(-2);
}
fop=fopen("svmip.txt","w");
if(fop == NULL){
printf("op err");
exit(-3);
}
for(i=1;i<=911;i++)
{
fgets(str,150,fin);
if((i>300&&i<=360)||(i>600&&i<=660))
str[7]='1';
else
str[7]='0';
fputs(str+7,fop);
// What is that for? should it be
// fputs(str, fop); ?????
// since you're outputting the 7'th character (1/0)?
putc('\n',fop);
}
fclose(fin);
fclose(fop);
if (str != NULL) free(str);
}
I have added logic checking to ensure if the file exists, to continue processing. Failure to do so will cause the code to blow up. Since in the original code, you were printing "ip err" if the input failed or in the case of output failure, yet continue on into the for loop which will render the execution to fail in that case as it would still be attempting to read from an non-existant file handle on failure.
Edit: Please see the comment above in the code. Are you trying to output 1/0's based on the conditional value of i between the ranges of 300-360 and 600-660 inclusively, into the output file. Can you clarify? Should that be
fputs(str[7], fop);
Hope this helps,
Best regards,
Tom.
Both fin=NULL and fop=NULL should both be using the 'equal-equal' operator. You're setting fin and fop to NULL instead of checking for a bad return value.