Access violation when searching through a file - c

This is my algorithm for searching a term into a file.
void ricerca_file(char* frase){
char* prelievo = "";
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){
if((strstr(prelievo, frase)) != NULL)
printf("frase trovata!\n");
}
fclose(file);
printf("%s", prelievo);}
i ask the input of frase in this way:
char* frase = "";
printf("insert the term that you want to search..");
scanf("%s", frase);
and then i call the function with:
ricerca_file(frase);
The compiler gives me this error after i write the input (e.g the number 2):
prove1.exe: 0xC0000005: Access violation writing location 0x00F67BC3.
If there is a handler for this exception, the program may be safely
continued.
What am i doing wrong?
if it wasn't clear, i'm learning. But i didn't really got how to manage the search of a term into a file.
I guess that with this algorithm i can miss lots of matches because if i search for "hello", with the strstr function that moves 5 characters per cycle if i have a file with a text like this "abchelloabc" he will first find "abche" and will not find anything, while after the first cycle it will go to the "lloab" part and then "c". Am i right thinking that it works like that and this is wrong?

prelievo points to a string literal. This is constant data that cannot be written to. And sizeof(prelievo) will be 2 or 4 (or whatever size pointers are on your system), which is not what you want.
You'll need to instead point prelievo to an array of characters that can be modified:
char prelievo[1000];
The same problems and solution apply to frase:
char frase[1000];

You need to actually provide memory to save the string you scan into. Try something like this instead:
char frase[80];
printf("insert the term that you want to search..");
fgets(frase, 80, stdin);
This allocates enough space for 80 characters and then reads one line of input.
Please also check the results of all these functions: If they return an error, you should act appropriately.

what am I doing wrong:
regarding:
char* prelievo = "";
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){
...
The call to fgets() needs to have a pointer to a buffer as its' first parameter.
The 'prelievo' is only an uninitalized pointer.
suggestion 1)
char* prelievo = malloc( 1024 );
if ( prelievo ) {
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){
suggestion 2)
char prelievo[1024];
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){

This answer is not exactly related to your problem, but because you already got your Answers i will try to explain you about some problems if you ignore them.
If we do not check for errors/return and the program works fine this does not mean that the program is ok or safe.
Let's take the following scenario as an Example.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char *printFile(char *fileName){
size_t length,size;
char *buffer;
FILE *file;
file = fopen (fileName , "r" );
fseek (file , 0 , SEEK_END);
length = (size_t)ftell (file);
fseek (file , 0 , SEEK_SET);
buffer = malloc(length);
if (buffer == NULL){
fputs ("Memory error",stderr);
exit (2);
}
size = fread (buffer,1,length,file);
if (size != length){
fputs ("Reading error",stderr);
exit(3);
}
fclose (file);
return buffer;
}
int main (void) {
char *fileName = "test.txt";
char *stringToSearch = "Addams";
char *fileContent = printFile(fileName);
if (strstr(fileContent, stringToSearch)){
printf("%s was Found\n",stringToSearch);
}else{
printf("%s was not Found\n",stringToSearch);
}
free(fileContent);
return 0;
}
The file test.txt has the following content:
Michael Jackson
Bryan Addams
Jack Sparrow
So now if I run this program I get:
Addams was Found
Everything seems to be ok, but what happens if I try to share this program with someone ? Or what happens if I try to run it on another computer ?
well:
Segmentation fault (core dumped)
OMG, what did just happen now ? Simple,the file test.txt is missing and i did not check that in my program that's why.
Lets move on and create that file and run that program again:
Addams was not Found
Huh, I succeeded isn't ? Well not, valgrind has another opinion:
==3657== Invalid read of size 1
==3657== at 0x4C32FF4: strstr (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3657== by 0x400A2D: main (in /home/michi/program)
==3657== Address 0x54202b0 is 0 bytes after a block of size 0 alloc'd
==3657== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3657== by 0x40095E: printFile (in /home/michi/program)
==3657== by 0x400A16: main (in /home/michi/program)
What happens is that I try to read a file which was newly created without thinking if that file has some content and i performed a lot of codding on it.

Related

heap-buffer-overflow with fprintf

I'm updating my question, very sorry for asking it the wrong way.
Now I could distill my problem into a single self-contained piece of code:
#include <stdio.h>
#include <stdlib.h>
static __inline__ char* fileRead(char* file){
FILE* fp;
long fileSize;
char* fileContents;
fp = fopen ( file , "rb" );
if(!fp){
perror(file);
exit(1);}
/* this block writes the size of the file in fileSize */
fseek( fp , 0L , SEEK_END);
fileSize = ftell( fp );
rewind( fp );
/* allocate memory for entire content */
fileContents = malloc(fileSize+1);
if(!fileContents){
fclose(fp);
fputs("memory alloc fails",stderr);
exit(1);}
/* copy the file into the buffer */
if(fread(fileContents, fileSize, 1, fp) != 1){
fclose(fp);
free(fileContents);
fputs("entire read fails",stderr);
exit(1);}
/* close the file */
fclose(fp);
return fileContents;}
int main (){
char* head10 = "";
char* fileName = "testhtml.html";
FILE* out = fopen(fileName, "w");
head10 = fileRead("head10.html");
printf("%s\n", head10);
out = fopen(fileName, "wb");
fprintf(out, "%s\n", head10);
fclose(out);
free(head10);
return 0;}
Here the head10.html file.
I'm compiling it with -fsanitize=address, and I'm getting an heap-buffer-overflow.
The error seems to be caused at the line fprintf(out, "%s\n", head10);.
head10 is the only malloc'd variable, so that makes sense.
I can print it without problems with printf, but when I try to write it to file with fprintf, an heap-buffer-overflow is generated.
===EDIT===
Looks like the problem came from using fprintf with a malloc'd var, as fprintf itself uses malloc under the hood, so the original alloc gets lost, and memory leaks.
So i rewrote my functions without using malloc:
#define _POSIX_C_SOURCE 200809L /* for getline() */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static __inline__ void fileReset(char* fileName){
FILE* out = fopen(fileName, "w");
fwrite("" , sizeof(char) , strlen("") , out );
fclose(out);}
static __inline__ void fileAppend(char* fileName, char* string){
FILE* out = fopen(fileName, "a"); /* using "a" to APPEND */
if(fwrite(string , sizeof(char) , strlen(string) , out ) != strlen(string)){
printf("==file write error\n");
exit(EXIT_FAILURE);}
fclose(out);}
static __inline__ void fileAppendFile(char* source, char* dest){
FILE* in = fopen(source, "r");
char *line = NULL;
size_t len = 0;
size_t read;
while ((read = getline(&line, &len, in)) != -1) {
fileAppend(dest, line);}
free(line);
fclose(in);}
int main (){
char* fileName = "testhtml.html";
char* theme = "dark";
fileReset(fileName);
fileAppendFile("head10.html", fileName);
fileAppend(fileName, theme);
return 0;}
Thanks a lot for all the help, very noob here, didn't know what -lasan was, now I know what an invaluable tool!
==EDIT-2==
As pointed out by EmployedRussian, the problem in the original code was NOT fprintf, but the lack of a terminating '\0', look at their answer below, it does fix my original code :)
Looks like the problem came from using fprintf with a malloc'd var, as fprintf itself uses malloc under the hood, so the original alloc gets lost, and memory leaks.
I am afraid you learned the wrong lesson here.
While fprintf may indeed use malloc under the hood, your problem doesn't have anything to do with that.
I created a head10.html file containing abc\n (4 characters). Running your program with that input file produced:
==10173==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000015 at pc 0x7fb5db2c7054 bp 0x7ffd44e74de0 sp 0x7ffd44e74590
READ of size 6 at 0x602000000015 thread T0
#0 0x7fb5db2c7053 (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x4d053)
#1 0x5654101dd435 in main /tmp/foo.c:43
#2 0x7fb5db0dde0a in __libc_start_main ../csu/libc-start.c:308
#3 0x5654101dd199 in _start (/tmp/a.out+0x1199)
0x602000000015 is located 0 bytes to the right of 5-byte region [0x602000000010,0x602000000015)
allocated by thread T0 here:
#0 0x7fb5db381628 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x107628)
#1 0x5654101dd2db in fileRead /tmp/foo.c:20
#2 0x5654101dd425 in main /tmp/foo.c:42
#3 0x7fb5db0dde0a in __libc_start_main ../csu/libc-start.c:308
So the problem is that you allocated 5 bytes (as expected), but fprintf tried to read 6th character from that buffer.
Why would it do that? Because the format you used: %s expects to find a terminating NUL character (i.e. it expects a properly terminated C-string), and you gave it a pointer to non-terminated string with the following bytes:
a b c \n X
What value does the fifth byte contain? It's undefined (it came from malloc, and no value was written into it). Since that value is not NUL, fprintf tries to read the next (6th) byte, and that's when Address Sanitizer signals the error and aborts your program.
The correct fix is to NUL-terminate the string, like so:
if (fread(fileContents, fileSize, 1, fp) != 1){ ... handle error
fileContents[fileSize] = '\0'; // NUL-terminate the string.

can't access a place in memory

I'm trying to read a binary file of 32 bytes in C, however I'm keep getting "segmentation fault (code dumped)" when I run my program,
it would be great if somebody can help me out by pointing where did I go wrong?.
my code is here below:
int main()
{
char *binary = "/path/to/myfiles/program1.ijvm";
FILE *fp;
char buffer[32];
// Open read-only
fp = fopen(binary, "rb");
// Read 128 bytes into buffer
fread (buffer, sizeof(char), 32, fp);
return 0;
}
It's because of the path. Make sure that "/path/to/myfiles/program1.ijvm" points to an existing file.
You should always check the return value of fopen.
\\Open read-only
fp = fopen(binary, "rb");
if(fp==NULL){
perror("problem opening the file");
exit(EXIT_FAILURE);
}
Notice also that you are reading 32 bytes in your buffer and not 128 as your comment says.
You must check the return result from fopen().
I'm assuming you are getting the segfault in the fread() call because your data file doesn't exist, or couldn't be opened, and you are trying to work on a NULL FILE structure.
See the following safe code:
#include <stdio.h>
#include <stdint.h>
#define SIZE_BUFFER 32
int main()
{
char *binary = "data.txt";
FILE *fp = NULL;
char buffer[SIZE_BUFFER];
// Open read-only
fp = fopen(binary, "rb");
// Read SIZE_BUFFER bytes into buffer
if( fp )
{
printf("Elements read %ld\n", fread (buffer, sizeof(char), SIZE_BUFFER, fp));
fclose(fp);
}
else
{
// Use perror() here to show a text description of what failed and why
perror("Unable to open file: ");
}
return 0;
}
When I execute this code it doesn't crash and will print the number of elements read if the file is opened or it will print "Unable to open file" if the file could not be opened.
As mentioned in the comments you should also close the file being exiting. Another thing you can do is the following:
FILE *fp = fopen(.....);
Instead of declaring and assigning in two separate steps.
There are two possible reasons
The fopen(3) function failed due to some reason, which means fp is NULL, and then you are trying to use the null-pointer in fread(3). This can crash. #OznOg has already given a subtle hint to look into this direction.
If the fopen call is a success (i.e. fp is non-NULL after calling fopen), the code can still crash because you are reading 32 chars into the variable binary, while binary has been initialized with only 30 chars.

C string modification

I came across a confused problem when I program in C
when i use oldPacket.filename = "fallout.jpg" //i have a file called fallout.jpg,and a struct called oldPakcet with an char* type filename
The program ran very well
Now, I decide to let user to in put the filename and also check the existence of the file. I wrote the following function:
bool Searchfile(packet* ptr) {
char userinput[100];
fgets(userinput, sizeof (userinput), stdin); //non terminated input by fgets
userinput[strcspn(userinput, "\n")] = 0;
//printf("%d\n",strlen(userinput));
ptr->filename = userinput + 4;//i skip the first 4 char since the correnct format is ftp <filename>
printf("%s\n",ptr->filename);
printf("%d\n",strlen(ptr->filename));
ptr->filename[strlen(ptr->filename)] = '\0';
if (access(ptr->filename, F_OK) != -1) {
printf("exist\n");
return false;
} else {
//printf("does not exist\n");
return true;
}
}
I call this function by
while (Searchfile(&oldPacket)){
printf("Please input the file name in the format: ftp <file name> \n");
}
However the program is no longer working and it shows seg fault at
int filesize;
fp = fopen(oldPacket.filename, "rb");
fseek(fp, 0L, SEEK_END);//here is the seg fault
Anyone have some idea why this happen ?
I already printf each char of the filename and it looks correct....
Thanks in advance
You let ptr->filename point to an address of local variable userinput, and accessing this value once userinput has gone out of scope is undefined behaviour.
The reason for the segfault is probably that the value of filename, when accessed outside of Searchfile, may be garbage, such that the file will not be opened. The subsequent fseek will then be called with a NULL-value for fp...
A simple solution to overcome this would be to write static char userinput[100];, at least when you are not working in a multithreaded environment. Otherwise you'd have to reserve memory for ptr->filename and copy contents of userinput.

How to edit a specific line of a txt file in C

I am currently trying to edit specific lines of .txt file in C. The file that im using looks like this :
Pixel location and RGB Color
Now lets say I want to change whats written on the specific line that its highlighted on the image:
400,300: (255,255,255) #FFFFFF
into this:
400,300: (000,000,000) #000000
Basically, im trying to create a black dot in specific pixels, in this case on 400,300. This is what i have of code:
#include <stdio.h>
int main(void)
{
const char *filename = "sample.txt";
int x = 400;
int y = 300;
FILE *fp;
fp = fopen(filename, "w+");
// Algorithm that reads all the file
// If("Operation that reads" == x+","+y)
// {
// Replace the line information after where it starts with "400,300"
// Like this : 400,300: (000,000,000) #000000
// }
// Algorithm that saves the file with the changes.
fclose(fp)
printf("Ok - File %s saved\n", filename);
return 0;
Creating, opening and editing .txt files is kind of new for me so I dont know what to do, the more i read about it, the more confused I get. How do I approach this problem and what code would fit here?
Update 1:
FILE *fp;
fp = fopen(filename, "w+");
if ( fp == NULL )
{
printf("Error while opening file");
}
Ok so after reading what you have placed below i came up with an idea but still needs work. I would print everything from the file to a char array. After that i would search in each slot for the specific line of code that I was looking for and keep the number slot. After that, i would go to array, run it, and when it comes to that specific slot, i would replace the needed data. Now all i needed to do is to swap the information thats in the file for the one thats in the array, save the file and problem solved. But im getting erros in the code and im missing the bits of code that would clear the txt file and save the new data.
Update 2:
#include <stdio.h>
int main(void)
{
int x,y;
int k = 0;
int noline; // Used to locate which line is the string im looking for
char search; // Used to compare with each string
char blackcode = (char)000; // In RGB, Black uses (000,000,000)
char blackhexcode = (char)000000; // The hexcode for black is #000000
const char *filename = "sample.txt";
char* strings[480000]; // Since its a 800x600 resolution picture, it needs that many lines.
char line[30]; // Space created to store whats inside each line of the file before transfering
char temp;
FILE * fp;
fp= fopen(filename, "r+");
if ( fp == NULL )
{
printf("Error while opening file");
}
else
{
while(fgets(line, sizeof line, fp))
{
strings[k]=strdup(line); // ERROR HERE! What Am I missing?
k++;
}
for(k = 0; k< sizeof strings; k++)
{
temp = scanf("%[^:]s", strings[k]);
search = ("%s,%s",x,y);
if(temp = search)
{
noline = k;
}
else
{
printf("Error : Wrong Coordinates");
}
}
for(k = 0; k < sizeof strings; k++)
{
if(k == noline)
{
strings[k] = ("%d,%d: (%s,%s,%s) #%s", x, y, blackcode, blackcode, blackcode, blackhexcode); // ERROR HERE! What did i did wrong?
}
}
// Code that cleans the txt file and saves the array back to txt file
}
fclose(fp);
}
What you are missing is somewhat conceptual, and somewhat related to fopen. When you think about opening a file with fopen, you need to pay particular attention to the effect of the file modes. If you look carefully at the man page regarding either "w" or "w+". In both cases the existing file is truncated. To 0-length in the case of "w".
To avoid this issue, one approach is to read the entire file into a buffer and then make changes to the buffer, writing the modified buffer back to the original filename. This avoids the possibility to attempting to insert/delete bytes without rewriting the remainder of the file.
To handle reading the file into a buffer, the link posted overwriting a specific line on a text file?, provides a roadmap to changing a single line in a file. Your case is different. You want to find/replace All occurrences of a particular pattern. (that is where the truncation issue posses challenges) However much of the solution there can be applied to reading the file itself into a buffer. Specifically the use of fseek and ftell.
Using fseek and ftell provides a simply way to determine the size (or length) of the file that can then be used to allocate space to hold the entire file in memory. Below is one approach to a simple function that takes the address of a character pointer and a file pointer, then using fseek and ftell allocates the required memory to hold the file and then reads the file into the buffer (filebuf) in a single operation with fread. The buffer is filled, in place, and also returned. A pointer to the file length fplen is passed to the function so the length is made available back in the calling function (main() in this case). Returning a pointer to the buffer on success (NULL otherwise) will allow assignment of the return, if desired, and a way to determine success/failure of the read:
char *read_file_into_buf (char **filebuf, long *fplen, FILE *fp)
{
fseek (fp, 0, SEEK_END);
if ((*fplen = ftell (fp)) == -1) { /* get file length */
fprintf (stderr, "error: unable to determine file length.\n");
return NULL;
}
fseek (fp, 0, SEEK_SET); /* allocate memory for file */
if (!(*filebuf = calloc (*fplen, sizeof *filebuf))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return NULL;
}
/* read entire file into filebuf */
if (!fread (*filebuf, sizeof *filebuf, *fplen, fp)) {
fprintf (stderr, "error: file read failed.\n");
return NULL;
}
return *filebuf;
}
Once you have the file in memory, the second piece of the puzzle is simply to scan through the buffer and make the replacements you need. Here there are a number of different tweaks you can apply to optimize the search/replace, but the following is just a straight forward basic search/replace where the only optimization attempt is a comparison of the starting character before using the normal string.h string comparison functions to check for your specified search string. The function returns the number of replacements made so you can determine whether a write out to the original filename is required:
unsigned find_replace_text (char *find, char *rep, char *buf, long sz)
{
long i;
unsigned rpc = 0;
size_t j, flen, rlen;
flen = strlen (find);
rlen = strlen (rep);
for (i = 0; i < sz; i++) {
/* if char doesn't match first in find, continue */
if (buf[i] != *find) continue;
/* if find found, replace with rep */
if (strncmp (&buf[i], find, flen) == 0) {
for (j = 0; buf[i + j] && j < rlen; j++)
buf[i + j] = rep[j];
if (buf[i + j])
rpc++;
}
}
return rpc;
}
Putting all the pieces together in a short example program using your sample data could be written as follows. The program expects the filename as the first argument (or it will read from stdin and write to stdout by default if no filename is given). There are always additional validation checks you can include as well:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
char *read_file_into_buf (char **filebuf, long *fplen, FILE *fp);
unsigned find_replace_text (char *find, char *rep, char *buf, long sz);
int main (int argc, char **argv) {
char *srchstr = "400,300";
char *repstr = "400,300: (000,000,000) #000000";
char *filebuf = NULL;
long int fplen = 0;
FILE *fp = NULL;
/* open file for reading (default stdin) */
fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open */
fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
return 1;
}
if (!read_file_into_buf (&filebuf, &fplen, fp)) return 1;
if (fplen < 1 || fplen >= INT_MAX) { /* validate file length */
fprintf (stderr, "error: length of file invalid for fwrite use.\n");
return 1;
}
if (fp != stdin) fclose (fp);
/* find/replace text in filebuf */
if (!find_replace_text (srchstr, repstr, filebuf, fplen)) {
printf ("no replacements made.\n");
return 0;
}
/* open file for writing (default stdout) */
fp = argc > 1 ? fopen (argv[1], "w") : stdout;
if (!fp) { /* validate file open */
fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
return 1;
}
/* write modified filebuf back to filename */
if (fwrite (filebuf, sizeof *filebuf, (size_t)fplen, fp) != (size_t)fplen) {
fprintf (stderr, "error: file write failed.\n");
return 1;
}
if (fp != stdout)
if (fclose (fp) == EOF) {
fprintf (stderr, "error: fclose() returned EOF\n");
return 1;
}
free (filebuf);
return 0;
}
Just include the functions at the bottom of the file. You can then:
Compile
gcc -Wall -Wextra -O3 -o bin/fread_file fread_file.c
(or use the equivalent compile string with your compiler)
Input File
$ cat dat/rbgtst.txt
400,280: (234,163,097) #EAA361
400,300: (255,255,255) #FFFFFF
400,320: (064,101,160) #4065A0
400,340: (220,194,110) #DCC26E
Use/File After Replacement
$ ./bin/fread_file dat/rbgtst.txt
$ cat dat/rbgtst.txt
400,280: (234,163,097) #EAA361
400,300: (000,000,000) #000000
400,320: (064,101,160) #4065A0
400,340: (220,194,110) #DCC26E
or reading from stdin writing to stdout:
$ ./bin/fread_file <dat/rbgtst.txt
400,280: (234,163,097) #EAA361
400,300: (000,000,000) #000000
400,320: (064,101,160) #4065A0
400,340: (220,194,110) #DCC26E
Memory/Error Check
In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an unintitialized value and finally to confirm that you have freed all the memory you have allocated.
For Linux valgrind is the normal choice. There are many subtle ways to misuse a new block of memory. Using a memory error checker allows you to identify any problems and validate proper use of of the memory you allocate rather than finding out a problem exist through a segfault. There are similar memory checkers for every platform. They are all simple to use, just run your program through it. E.g.:
$ valgrind ./bin/fread_file dat/rbgtst.txt
==13768== Memcheck, a memory error detector
==13768== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==13768== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==13768== Command: ./bin/fread_file dat/rbgtst.txt
==13768==
==13768==
==13768== HEAP SUMMARY:
==13768== in use at exit: 0 bytes in 0 blocks
==13768== total heap usage: 3 allocs, 3 frees, 2,128 bytes allocated
==13768==
==13768== All heap blocks were freed -- no leaks are possible
==13768==
==13768== For counts of detected and suppressed errors, rerun with: -v
==13768== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
You want to confirm All heap blocks were freed -- no leaks are possible and ERROR SUMMARY: 0 errors from 0 contexts (ignore the suppressed note which simply relates to missing debug symbol files not installed on my system)
Look over the code and understand what it is doing. This isn't presented as the only way of doing what you are attempting to do, but it is presented as an example of how to approach the problem while avoiding a number of pitfalls inherent in trying to change a line-at-a-time in an existing file utilizing offsets and a number of reads/writes to the file. Let me know if you have questions.
You cannot write specific line of txt file in general.
Actually, txt file is just a sequence of bytes. Every line separated by each other just by special symbol '\n' (or symbols '\r', '\n': there are two approaches).
So, if you rewrite some line, you have to move data (lines) remained in the file just after your new line.
But if your new line has the same length as before, you can write it over old line without any worries.
The best approach I can think of for something like this is to open the file in read only mode and then copy everything to a new folder by opening a new file in 'w+' mode. Then you go line by line in the read file until you find a line that you wish to change, then you rewrite the line yourself in the new copy file. Then skip that line in the read file and continue on.
After the copy file is what you want, you can replace the name of it to the original file name you want it to have. Then it will act as if you edited the file like you wanted to.

Reading file line by line with fgets in C, invalid read of size [duplicate]

This question already has answers here:
Valgrind on OS X Yosemite, giving bogus errors? [duplicate]
(4 answers)
Closed 7 years ago.
I keep getting a valgrind error in my code, and after three hours I remain clueless so I need your help people.
So I basically just read files contained in a directory and parse them, So I copied the shortest example of my code still producing the error:
int main(int argc, char** argv) {
parse_files_dir("/Users/link_to_dir_example/");
return (EXIT_SUCCESS);
}
void parse_files_dir(char *dirLink){
int dLink_l =strlen(dirLink);
int max_len = dLink_l*2;
char* full_path=malloc(sizeof(char)*(max_len+1));
//check if null pointer...
strncpy(full_path, dirLink, dLink_l);
DIR *dir;
struct dirent *dir_con;
dir=opendir(dirLink);
if (dir == NULL){
fprintf(stderr, "Problem opening directory: \"%s\". Aborting...\n", dirLink);
exit(EXIT_FAILURE);
}
while((dir_con = readdir(dir)) != NULL){
if (dir_con->d_name[0] == '.') continue;
if (dLink_l+strlen(dir_con->d_name)>max_len) //realloc full path..
strncpy(&full_path[dLink_l], dir_con->d_name, strlen(dir_con->d_name));
full_path[dLink_l+strlen(dir_con->d_name)] = '\0';
parse_one_file(full_path); // (*) <=== valgrind complain
full_path[dLink_l] = '\0';
}
free(full_path);
closedir(dir);
}
So now the actual problem method:
void parse_one_file(char* link) {
FILE *file = fopen(link, "r");
if (file == NULL) //error message
int line_len=0;
int line_max=1000;
char* line= malloc(sizeof(char)*line_max);
line[0] = '\0';
char* line_full= malloc(sizeof(char)*line_max);
line_full[0] = '\0';
int line_full_len = 0;
//check all allocations for null pointers
while(fgets(line, line_max, file) != NULL){ // <=== Here is where valgrind complains !!!!
line_len = strlen(line);
if (line[line_len-1] == '\n'){
strncpy(&line_full[line_full_len], line, line_len);
line_full_len+=line_len;
}
else{
//Check if line_full has enough memory left
strncpy(&line_full[line_full_len], line, line_len);
line_full_len+=line_len;
}
line[0] = '\0';
}
free(line);
free(line_full);
fclose(file);
}
I keep getting the error:
==4929== Invalid read of size 32
==4929== at 0x1003DDC1D: _platform_memchr$VARIANT$Haswell (in /usr/lib/system/libsystem_platform.dylib)
==4929== by 0x1001CF66A: fgets (in /usr/lib/system/libsystem_c.dylib)
==4929== by 0x100000CD8: parse_one_file (main.c:93)
==4929== by 0x100000B74: parse_files_dir (main.c:67)
==4929== by 0x100000944: main (main.c:28)
==4929== Address 0x100804dc0 is 32 bytes before a block of size 4,096 in arena "client"
So i really dont see where my mistake is, I keep emptying the buffer line, I never read more bytes than allocated there.
The interesting thing I noticed is, if the directory "dirLink" has only one file, the error does not occur, however if I have two or more, the error occurs, so I thought the mistake is how I generate the path "full_path", but then I replaced line "*" with (just for testing reasons)
parse_one_file("another/example/path/");
and the error remained..
Unless your file is less than 1000 bytes in total you are writing over the end of the line_full buffer which is only 1000 bytes total in size. This will invariably clobber your memory and lead to spurious errors like the one you experience in fgets.
if(line[line_len-1] == '\n'){
strncpy(&line_full[line_full_len], line, line_len);
line_full_len+=line_len;
}
This is not quite correct, you can only strncpy() (line_max - line_full_len) bytes, there is no guarantee that you can copy line_len bytes. Or in other words. starting from position line_full[500], you can't write another 1000 bytes.
The same error is in the else branch.

Resources