Segmentation fault when reading a binary file into a structure - c

I'm experiencing some problems while trying to read a binary file in C.
This problem never happened to me before, I don't really know how to manage it.
So, there's this structure called "hash_record", there are many of them stored in my "HASH_FILE" file in binary mode. This is the structure:
typedef struct hash_record {
char *hash;
char *filename;
} hash_record;
I write the file in this way:
hash_record hrec;
[...] code that fill the structure's fields [...]
FILE* hash_file = fopen(HASH_FILE, "ab");
fwrite(&hrec, sizeof(hash_record), 1, hash_file);
fclose(shared_file);
This is just a summary, the fwrite() function is inside a loop so that I can fill the file with many hash_record's.
Then, immediately after that piece of code, I start reading the file and printing some data to be sure everything went well. This is the code:
int print_data() {
hash_record rec;
printf("Data:\n");
FILE* hash_file = fopen("hash.bin", "rb");
if (hash_file == NULL)
return -1;
while(fread(&rec, sizeof(hash_record), 1, hash_file) == 1)
printf("Filename: %s - Hash: %s", rec.filename, rec.hash);
fclose(hash_file);
return 0;
}
And everything works just fine!
The problem is that if I write the binary file in an instance of my program and then quit it, when I open it again (commenting the code which write the file so it can only read it) it gives me a Segmentation Fault. This error appears when I call the printf() inside the while() loop. If I just print a common string without calling "rec" no errors are given, so I'm assuming there's something wrong storing data inside "rec".
Any idea?
Thank you!

You are writing out pointers. When you read them back in from the same instance of the program, the data is in the same place and the pointers are meaningful. If you read them in from another instance, the pointers are bad.

Related

Can someone help me determine the cause of my Seg Fault in C and the meaning of the gdb output?

When I run the program it prints out "SUCCESS!!!!" if it works alright, but I keep getting seg faults and I can't seem to figure out where. Can someone help me determine what exactly causes the signal SIGABRT and what is the most likely cause of why getting segmentation faults?
My code is written in c.
EDIT:
In my main code on line 97 I have the function fclose(fp) but I should have already read through it in another function. Here is my code from main.c:
FILE *fp = NULL;
if(fp = fopen(full_filename, "r")){
Node* tree = NULL;
tree = parser(fp);
printTree(tree, 1);
fclose(fp);
}
else
printf("Error file DNE\n");
return 0;
The function parser gets the file pointer and sends that file pointer to another function called scanner. Then scanner creates a list of words from that file. Then parser checks grammar of the words.
EDIT 2:
I got rid of fclose(fp) in main and when I ran it in gdb, I got no errors. But when I ran it without gdb I still get a seg fault.
There isn't too much information, but looking at the trace it would be my guess that you are trying to close a file with fclose() or iofclose(), and the file may not exist, or it is not open.
Conclusion
The problem must lie in your parser() function. It seems it is altering your file pointer and making it invalid.
Explanation
I state this because I it can't enter your if(fp = fopen(full_filename, "r")) statement unless the pointer is valid, but when you try to close it, the pointer seems to be invalid.
Note that
The only line which is able to affect your pointer is the one showing the folowing:
tree = parser(fp);

fgetc() Creating Segmentation Fault

I made the file "wor.txt" in the same program and i closed its write stream. But when i try to access it in first run(I created the file) it gives segmentation fault but when i re-run this program it runs successfully.
When i delete the automatically generated file and run the program again it gives Segmentation fault and on 2nd run(Without deleting the file) it runs successfully again.
NOTE: There is data in the textfile hence it is not empty(I have seen it after the first run in the file manager)
FILE *fp1= fopen("wor.txt","r");
FILE *f1= fopen("wordsa.txt","ab+");
if((f1==NULL)||(f2==NULL)){
printf("f1 or f2 is null");
}
char c='0';
while((c)!=EOF){
printf("Here is one marker\n");
c=fgetc(fp1); //This Line gives error
printf("Here is another marker\n");
fputc(c,f1);
}
A char is no sufficient for EOF, change the type to int.
Check the man page of fgetc(), it returns an int and you should use the same datatype for storing the return value and further use.
That said, when either of f1 or fp1 is NULL, you are continuing anyways, accessing those file pointers, which may create UB. You should make some sense of that NULL check and either return or exit so that the code accessing tose pointers are not reached.
Incorrect check.
To properly detect opening of the stream, check fp1, not f2. Then code will fail gracefully when the files do not open properly rather than seg fault.
FILE *fp1= fopen("wor.txt","r");
FILE *f1= fopen("wordsa.txt","ab+");
// if((f1==NULL)||(f2==NULL)){
if((f1==NULL) || (fp1==NULL)){
printf("f1 or fp1 is null");
}
Also use int c as fgetc() typically returns 256 + 1 different values (unsigned char values and EOF) and a char is insufficient to uniquely distinguish them.

C - Unlink/Remove produces error for filenames with spaces

I am trying to make a function in C to erase all the contents of a temp folder and to erase the folder.
Whilst I already have successfully created the code to cycle through the files and to erase the folder (it is pretty much straight forward) I am having trouble erasing the files using unlink.
Here is the code that I am using:
int delete_folder(char *foldername) {
DIR *dp;
struct dirent *ep;
dp=opendir(foldername);
if (dp!=NULL) {
readdir(dp); readdir(dp);
while (ep=readdir(dp)) {
char* cell = concatenate(concatenate(foldername, "\\"), "Bayesian Estimation.xlsx");//ep->d_name);
printf("%s\n", cell);
remove(cell);
printf("%s\n", strerror(errno));
}
closedir(dp);
}
if (!rmdir(foldername)) {return(0);} else {return(-1);}
}
The code that I wrote is fully functional for all files but those which include spaces in the filename. After some testing, I can guarantee that the unlink functions eliminates all files in the folder (even those with special characters in the filename) but fails if the filename includes a space (however, for this same file, if I remove the space(s), this function works again).
Has anyone else encountered this problem? And, more importantly, can it be solved/circunvented?
(The problem remains even if I introduce the space escape sequences directly)
The error presented by unlink is "No such file or directory" (ENOENT). Mind you that the file is indeed at the referred location (as can be verified by the code outputing the correct filename in the variable cell) and this error also occurs if I use the function remove instead of unlink.
PS: The function concatenate is a function of my own making which outputs the concatenation of the two input strings.
Edit:
The code was written in Codeblocks, in Windows.
Here's the code for the concatenate function:
char* concatenate(char *str1, char *str2) {
int a1 = strlen(str1), a2 = strlen(str2); char* str3[a1+a2+1];
snprintf(str3, a1+a2+2, "%s%s", str1, str2);
return(str3);
}
Whilst you are right in saying that it is a possible (and easy) memory leak, the functions' inputs and outputs are code generated and only for personal use and therefore there is no great reason to worry about it (no real need for foolproofing the code.)
You say "using unlink()" but the code is using remove(). Which platform are you on? Is there any danger that your platform implements remove() by running an external command which doesn't handle spaces in file names properly? On most systems, that won't be a problem.
What is a problem is that you don't check the return value from remove() before printing the error. You should only print the error if the function indicates that it generated an error. No function in the Standard C (or POSIX) library sets errno to zero. Also, errors should be reported on standard error; that's what the standard error stream is for.
if (remove(cell) != 0)
fprintf(stderr, "Failed to remove %s (%d: %s)\n", cell, errno, strerror(errno));
else
printf("%s removed OK\n", cell);
I regard the else clause as a temporary measure while you're getting the code working.
It also looks like you're leaking memory like a proverbial sieve. You capture the result of a double concatenate operation in cell, but you never free it. Indeed, if the nested calls both allocate memory, then you've got a leak even if you add free(cell); at the end of the loop (inside the loop, after the second printf(), the one I deconstructed). If concatenate() doesn't allocate new memory each time (it returns a pointer to statically allocated memory, then I think concatenating a string with the output of concatenate() is also dangerous, probably invoking undefined behaviour as you copy a string over itself. You need to look hard at the code for concatenate(), and/or present it for analyis.
Thank you very much for all your input, after reviewing your comments and making a few experiments myself, I figured out that remove/unlink was not working because the filename was only temporarily saved at variable cell (it was there long enough for it to be printed correctly to console, hence my confusion). After appropriately storing my filename before usage, my problem has been completely solved.
Here's the code (I have already checked it with filenames as complex as I could make them):
int delete_folder(char* foldername) {
DIR *dp;
struct dirent *ep;
dp=opendir(foldername);
if (dp!=NULL) {
readdir(dp); readdir(dp);
while (ep=readdir(dp)) {
char cell[strlen(foldername)+1+strlen(ep->d_name)+1];
strcpy(cell, concatenate(concatenate(foldername, "\\"), ep->d_name));
unlink(cell);
printf("File \"%s\": %s\n", ep->d_name, strerror(errno));
}
closedir(dp);
}
if (!rmdir(foldername)) {return(0);} else {return(-1);}
}
I realize it was kind of a noob mistake, resulting from my being a bit out of practice for a while in programming in C, so... Thank you very much for your all your help!

File IO does not appear to be reading correctly

Disclaimer: this is for an assignment. I am not asking for explicit code. Rather, I only ask for enough help that I may understand my problem and correct it myself.
I am attempting to recreate the Unix ar utility as per a homework assignment. The majority of this assignment deals with file IO in C, and other parts deal with system calls, etc..
In this instance, I intend to create a simple listing of all the files within the archive. I have not gotten far, as you may notice. The plan is relatively simple: read each file header from an archive file and print only the value held in ar_hdr.ar_name. The rest of the fields will be skipped over via fseek(), including the file data, until another file is reached, at which point the process begins again. If EOF is reached, the function simply terminates.
I have little experience with file IO, so I am already at a disadvantage with this assignment. I have done my best to research proper ways of achieving my goals, and I believe I have implemented them to the best of my ability. That said, there appears to be something wrong with my implementation. The data from the archive file does not seem to be read, or at least stored as a variable. Here's my code:
struct ar_hdr
{
char ar_name[16]; /* name */
char ar_date[12]; /* modification time */
char ar_uid[6]; /* user id */
char ar_gid[6]; /* group id */
char ar_mode[8]; /* octal file permissions */
char ar_size[10]; /* size in bytes */
};
void table()
{
FILE *stream;
char str[sizeof(struct ar_hdr)];
struct ar_hdr temp;
stream = fopen("archive.txt", "r");
if (stream == 0)
{
perror("error");
exit(0);
}
while (fgets(str, sizeof(str), stream) != NULL)
{
fscanf(stream, "%[^\t]", temp.ar_name);
printf("%s\n", temp.ar_name);
}
if (feof(stream))
{
// hit end of file
printf("End of file reached\n");
}
else
{
// other error interrupted the read
printf("Error: feed interrupted unexpectedly\n");
}
fclose(stream);
}
At this point, I only want to be able to read the data correctly. I will work on seeking the next file after that has been finished. I would like to reiterate my point, however, that I'm not asking for explicit code - I need to learn this stuff and having someone provide me with working code won't do that.
You've defined a char buffer named str to hold your data, but you are accessing it from a separate memory ar_hdr structure named temp. As well, you are reading binary data as a string which will break because of embedded nulls.
You need to read as binary data and either change temp to be a pointer to str or read directly into temp using something like:
ret=fread(&temp,sizeof(temp),1,stream);
(look at the doco for fread - my C is too rusty to be sure of that). Make sure you check and use the return value.

File returns garbage, but writes correctly

I'm writing a struct into a file, but it returns garbage. Here is my code:
ptFile = fopen("funcionarios.dat", "ab+");
fwrite(&novoFunc, sizeof(strFunc), 1, ptFile);
The values of struct novoFunc, before and after the fwrite are not garbage.
However, when I return the file values:
ptFile = fopen("funcionarios.dat", "rb+");
[...]
fseek(ptFile, i*sizeof(strFunc), SEEK_SET); //on the loop, i goes from 0 to total structs
fread(&funcionario, sizeof(strFunc), 1, ptFile);
printf("Code: %d; Name: %s; Address: %s; CPF: %d; Sales: %d\n", funcionario.codigo, funcionario.nome, funcionario.endereco, funcionario.cpf, funcionario.numVendas);
Any idea why? The code was working fine, and I dont remember doing significative changes.
Thanks in advance
Edit: Struct definition
typedef struct func{
int codigo;
char nome[50];
char endereco[100];
int cpf;
int numVendas;
int ativo;
} strFunc;
Edit2: It just got weirder: it works fine on linux (using netbeans and gcc compiler), but it doesnt on windows (devcpp and codeblocks). Well, the entire code is here:
http://pastebin.com/XjDzAQCx
the function cadastraFucionario() register the user, and when I use listaFuncionarios(), to list all the registered data, it returns the garbage. Here is a print of what listaFuncionarios() returns:
http://img715.imageshack.us/img715/3002/asodfadhf.jpg
Im sorry the code isnt in english
You say: "The code was working fine, and I dont remember doing significative changes."
When it was working fine, it wrote some structures into your file.
Maybe later it was still working fine, and it appended some additional structures at the end of your file. The original data still remained at the beginning of your file. So when you read the beginning of the file, you read the original data. Maybe.
Are you sure that you read garbage? Are you sure that you didn't just read old data?
In your code:
ptFile = fopen("funcionarios.dat", "ab+");
Appending is the right thing to do for some purposes but not for others. Do you need wb+ instead?
This:
it works fine on linux ... but it doesnt on windows
is a big red flag. Windows has "text" files which are different to "binary" files. On Linux and other Unixes, there is no difference.
Two lines in your source stand out:
fopen("funcionarios.dat", "rb+");
and later
fopen("funcionarios.dat", "r+");
That is, sometimes you open the file in "binary" mode, and sometimes in "text" mode. Make sure you always open any file in "binary" mode (that is, with the b in the mode string) if you ever intend to read or write non-text data.
Here are two problems in your function retornaIndice.
while(!feof(ptFile)){
fseek(ptFile, sizeof(strFunc)*i, SEEK_SET);
fread(&tmpFunc, sizeof(strFunc), 1, ptFile);
You aren't checking the result of fread. After reading the last record, eof has not been reached yet, so you will try another read. That read will reach eof and will return 0, but you aren't checking for that 0, so you will use garbage data and will exit the loop the next time the while statement tests it.
if(codigo != 0 && tmpFunc.ativo){
if(tmpFunc.codigo == codigo){
return i;
}
If you detect a problem at this point, you don't close ptFile. The leaked handle shouldn't cause garbage data to be written to the file, but it doesn't inspire confidence either.
Some of your other functions have the same errors.

Resources