unexpected seg fault caused by lstat function - c

i'm making na assignment for programming class.
The program is supposed to:
receive a string from command line.
open the current directory and cycle through its entries,
and analyse the entries only if their name starts with
the string that i passed from CMD.
if these entries are regular files,
i need to count all characters except spaces,
and count the number of words that start with a/A.
Here's the code.
int main(int argc,char* argv[])
{
if(argc!=2) //ensures at least an argument is passed.
{
puts("enter one argument.");
exit(EXIT_FAILURE);
}
DIR* folder; //folder abstraction
struct dirent* entry; //entry abstraction
struct stat info; //file's i node info
FILE* file;
int total=0,first=0;
char temp[100];
int res;
folder=opendir("."); //i open the directory
while((entry=readdir(folder))!=NULL) //i cicle through every entry
{
res=strncmp(entry->d_name,argv[1],strlen(argv[1]));
if(res==0) //if entry name begins with string i continue
{
lstat(entry->d_name,&info); //i take file info
if(S_ISREG(info.st_mode)) //i check if it's a regular file
{
file=fopen(entry->d_name,"r"); //i open it
//printf("%s\n",entry->d_name);
while((fscanf(file,"%s",temp))!=EOF) //i parse it
{
if(temp[0]=='a'|| temp[0]=='A')
{
first++;
}
total+=strlen(temp);
}
//now i close the file and print all info
fclose(file);
printf("%s\nthe number words that start with a/A: %i\n",entry->d_name,first);
printf("the amount of characters except spaces is %i\n",total);
total=0;
first=0;
}
}
//now the process will be repeated for the remaining entries
}
return 0;
}
the problem is, the program gets the first entry that starts with the pattern that i passed from CMD, evaluates it correctly, but then
when the stat is called on the second entry, it causes seg fault 11.
if i comment out the lstat, all the entries that match the criteria are recognized, even if no calculation i can't test if it's regular file without lstat...
what is causing the issue, i've been trying stuff for the past two hours, please help me, thanks!
EDIT:
I found the problem, basically the directory I'm working in has binary files of executables.
It turns out that binary files are considered regular files, so when the program opened it to parse it, it parsed one long string that caused buffer overflow on the temp variable. I thought those files were binary and separated from regular.

unexpected seg fault caused by lstat function
With undefined behavior in other parts of code, we do not know the seg fault is caused by lstat. Inclusion of lstat did reveal a problem, yet the true cause may lie elsewhere.
Code has troubles yet it lacks error checking in various places. #Weather Vane
Check function return values
folder=opendir(".");
if (folder == NULL) {
perror("opendir failed);
exit (EXIT_FAILURE);
}
// lstat(entry->d_name,&info);
if (lstat(entry->d_name,&info)) {
perror("lstat failed);
exit (EXIT_FAILURE);
}
file=fopen(entry->d_name,"r");
if (file == NULL) {
fprintf(stderr, "Unable to open <%s> for reading\n", entry->d_name);
exit (EXIT_FAILURE);
}
Limit width
// while((fscanf(file,"%s",temp))!=EOF)
while(fscanf(file,"%99s",temp) == 1) {
if (strlen(temp) == 99) {
fprintf(stderr, "Maximum length word read, longer ones might exist\n");
exit (EXIT_FAILURE);
}
Of course instead of exiting, code cab handle the error in some other way.
Minor: I'd used width types for counting characters.

Related

Pipe's write overwrites an allocated space of memory

My program it's pretty big, so I'll highlight the main problem and add some details about it.
First part of my code:
int myPipe[2]; //A global variable, so I don't have to pass it to future functions
int main(int argc, char *args[])
{
mode_t pUmask = umask(0000); //Obsolete variable to my problem
errno = 0; //Obsolete variable to my problem
char pattern[2500] = "Test1"; //Obsolete variable to my problem
int p = 0; //DEFAULT NUMBER OF PROCESSES
int deep = 0; //Obsolete variable to my problem
int n = 1; //Obsolete variable to my problem
if(pipe(myPipe))
{
perror("Pipe Error: ");
exit(-1);
}
if( (write(myPipe[1], &p, (sizeof(int)*3))) == -1) //First write works
{
perror("write: ");
exit(-1);
}
//Then a bunch of code releated to file reading
}
Second part:
{
//in another function
//The part where I create fileName
char* fileName = calloc(strlen(fileData->d_name)+4, sizeof(char));
strcpy(fileName, fileData->d_name);
}
Third part:
//in another another function
if(S_ISREG(data.st_mode))
{
printf("\tfileName: %s\n", fileName); //Regular print of the right fileName
printf("\t\tOh boy! It's a regular.\n");
printf("\tfileName: %s\n", fileName); //Regular print of the right fileName
if((read(myPipe[0], &p, (sizeof(int)*3))) == -1) //First time I read
{
perror("\t\t read: ");
exit(-1);
}
printf("fileName: %s", fileName); //SEGMENTATION FAULT
There is a bunch of code in between, but it doesn't affect the fileName at all (in fact, up until the "read", fileName was printed flawlessly), and after it a SEGMENTATION FAULT happens.
At one point by changing the printfs locations I was able to get the fileName AFTER the read, which was basically the fileName value("File1") followed by the p integer value(0), which created the new corrupted fileName("File10").
So what's happening? I reserved the space for fileName, I passed the fileName pointer to the following functions up to that read, and supposedly the fd should have it's own adress space as well. HELP.
P.s. if you need more info, I'm willing to give it to you, even the full code, but it's REALLY complicated, and I think I gave you enough proof that fileName doesn't get corrupted at all until the read part, THANK YOU.
P.p.s.
I never close either of the "MyPipe" extremes, since I have to use them multiple times, I wanted to close them at the end of the program.
The statements that write and read the pipe are causing undefined behavior. p is declared:
int p;
But when you write and read it through the pipe, you use sizeof(int)*3, so you're accessing outside the object.
Change those statements to use just sizeof p.

Reading all files in two directories at the same time

I have a problem with task. I have two path to directories. I can read all files from first path in argv[1] but can't open files from second folder from argv[2]. Quantity of files is equal. The way at the begining to write name of fales in array is failed because their is about a few hundred.I have an example how I try reading files. Need help. Thanks!
#include "stdafx.h"
#include "windows.h"
int main(int argc, char* argv[])
{
FILE *fp = 0;
uchar tmpl1[BUFFER_SIZE] = { 0 };
uchar tmpl2[BUFFER_SIZE] = { 0 };
size_t size;
size_t n;
FILE *Fl = 0;
if (argc != 3 || argv[1] == NULL || argv[2] == NULL)
{
printf("Error", argv[0]);
return -1;
}
char Fn[255];
HANDLE hFind;
WIN32_FIND_DATA ff;
char Fn1[255];
HANDLE hFind1;
WIN32_FIND_DATA ff1;
sprintf_s(Fn, 255, "%s\\*", argv[1]);
sprintf_s(Fn1, 255, "%s\\*", argv[2]);
if ((hFind = FindFirstFile(Fn, &ff)) != INVALID_HANDLE_VALUE)
{
if ((hFind1 = FindFirstFile(Fn1, &ff1)) != INVALID_HANDLE_VALUE)
{
do
{
if (ff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
ff1.dwFileAttributes;
sprintf_s(Fn, "%s\\%s", argv[1], ff.cFileName);
sprintf_s(Fn1, "%s\\%s", argv[2], ff1.cFileName);
// here I can't read file's name from second folder
printf(Fn, "%s\\%s", argv[1], ff.cFileName);
printf(Fn1, "%s\\%s", argv[2], ff1.cFileName);
if (fopen_s(&fp, Fn, "rb") != 0)
{
printf("Error reading\nUsage: %s <tmpl1>\n", argv[1]);
return -1;
}
size = _filelength(_fileno(fp));
n = fread(tmpl1, size, 1, fp);
fclose(fp);
fp = 0;
} while (FindNextFile(hFind, &ff));
// also I have a problem how read next file in second directory
FindClose(hFind);
}
}
return 0;
}
I didn't read why you want to scan two directories concurrently.
When I saw "at the same time" in the title I thought "concurrently". Afterwards, I saw the presented code and realized it shall be done rather "interleaved" instead of "concurrently" but that's not essential.
I assume you want to associate the file names in the first directory somehow to the file names in the second directory. This might be comparing the file names, read data from a file of first directory and read other data from an associated file of second directory, or may be something completely different.
However, based on this assumption, you have to consider that:
You should not assume to get file names in any useful order when scanning with FindFirstFile()/FindNextFile(). These functions return the files in its "physical order" i.e. how they are listed internally. (At best, you get . and .. always as first entries but I even wouldn't count on this.)
Considering this, I would recommend the following procedure:
read file names from first directory and store them in an array names1
read file names from second directory and store them in an array names2
sort arrays names1 and names2 with an appropriate criterion (e.g. lexicographically)
process the arrays names1 and names2.
As you see, the "read file names from directory and store them in an array" could be implemented as function and re-used as well as the sorting.
This said, finally, the answer for how to interleave two directory scans:
HANDLE hFind1 = FindFirstFile(Fn1, &ff1);
HANDLE hFind2 = FindFirstFile(Fn2, &ff2);
while (hFind1 != INVALID_HANDLE_VALUE || hFind2 != INVALID_HANDLE_VALUE) {
if (hFind1 != INVALID_HANDLE_VALUE) {
/** #todo process ff1 somehow */
}
if (hFind2 != INVALID_HANDLE_VALUE) {
/** #todo process ff2 somehow */
}
/* iterate: */
if (!FindNextFile(hFind1, &ff1)) {
FindClose(hFind1); hFind1 = INVALID_HANDLE_VALUE;
}
if (!FindNextFile(hFind2, &ff2)) {
FindClose(hFind2); hFind2 = INVALID_HANDLE_VALUE;
}
}
Please, note that I "abuse" the handles hFind1 and hFind2 itself for loop repetition. Thus, I do not need the extra ifs. (I like things like that.)
Btw. this loop iterates until both directories are scanned completely (even if they don't contain the same number of entries).
If you want to iterate instead until at least one directory is scanned completely you may achieve this by simply changing the while condition to:
while (hFind1 != INVALID_HANDLE_VALUE && hFind2 != INVALID_HANDLE_VALUE) {
if the loop shall be terminated as soon as at least one directory scan fails.
At last, a little story out of my own past (where I learnt a useful lesson regarding this):
I just had finished my study (of computer science) and was working at home on a rather fresh installed Windows NT when I started to copy a large directory from a CD drive to harddisk. The estimated time was round-about 1 hour and I thought: 'Hey. It does multi-tasking!' Thus, I started a second File Manager to copy another directory from this CD drive concurrently. When I hit the OK button, the prompt noises of the CD drive alerted me as well as the estimated time which "exploded" to multiple hours. After that, I behaved like to expect: tapped on my forehead and mumbled something like "unshareable resources"... (and, of course, stopped the second copying and went for a coffee instead.)

fopen doesn't open

I am using Code::Blocks and have set the command-line arugments via the IDE. I have also opened the executable with the proper argument and I can't manage to get a non-NULL on fopen() return. I've tried hard-coding the filename also with no success. The platform is Windows XP SP3.
The first is the one that fails, when i hardcoded it i used double backlash. Also i never knew if the second works because i never managed to start the process by opening the first one.
Obviously i put the text file in the same directory that the executable and rebuilt the executable many times, but it still doesn't work.
EDIT: I added the perror("fopen"); line in the if(finput==NULL) block. This is the output.
http://prntscr.com/h71pa
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define first_part_url "[url=http://magiccards.info/query?q="
#define second_part_url "&v=card&s=cname]"
#define end_bracket "[/url]\n"
#define output_file_prefix "output_"
char* get_card(FILE* finput);
int main(int n, char* arguments[])
{
FILE* finput;
FILE* foutput;
short int counter;
char* output_filename;
char* finalstring;
for(counter=1; counter<n; counter++)
{
finput=fopen(arguments[counter], "r");
if (finput==NULL)
{
printf("Unable to open ");
puts(arguments[counter]);
perror("fopen");
break;
}
strcpy(output_filename, output_file_prefix);
strcat(output_filename, arguments[counter]);
if((foutput=fopen(output_filename, "w"))==NULL)
{
printf("There was an error while trying to open ");
puts(arguments[counter]);
printf(" .\n");
break;
}
while(!feof(finput))
{
finalstring=get_card(finput);
fputs(finalstring, foutput);
while(((fgetc(finput))!='\n')||feof(finput));
}
printf("Autocarding ");
puts(arguments[counter]);
printf(" was a success.\n");
fclose(foutput);
}
if(finput!=NULL)
{
fclose(finput);
free(finalstring);
}
return 0;
}
char* get_card(FILE* finput)
{
char* currentcard;
char* finalstring;
currentcard=(char*)malloc(sizeof(char)*150);
fgets(currentcard, 150, finput);
/* Allocates the exact amount of space needed for the final string*/
finalstring=(char*)malloc(sizeof(char)*(strlen(first_part_url)+strlen(second_part_url)+strlen(end_bracket)+strlen(currentcard)));
/* Get all the final forum link together*/
strcat(finalstring, first_part_url);
strcat(finalstring, currentcard);
strcat(finalstring, second_part_url);
strcat(finalstring, end_bracket);
free(currentcard);
return finalstring;
}
The error you are getting, "No such file or directory" indicates that the file name you're trying to open doesn't exist.
In this case, it's probably because the program's current working directory is not the same as the directory containing the executable file.
This
finput=fopen(arguments[counter], "r");
Will only fail if you do not supply correct filenames (e.g. if there are non-ASCII characters in the names or the names do not include the correct path, fopen() opens files in the current directory if no path is specified in the file name).
This
output_filename=(char*)malloc(sizeof(arguments[counter]));
most likely does not allocate enough space for a name because arguments[counter] is a pointer, and sizeof() of a pointer is not the same as strlen(that_same_pointer) + 1.
This
output_filename=output_file_prefix;
loses the just allocated memory because you are reassigning the pointer output_filename to point to some other place, output_file_prefix ("output_").
After the above this
strcat(output_filename, arguments[counter]);
is likely going to crash your program because this is going to attempt to overwrite a string literal ("output_"), doing which causes undefined behavior per the C standard.
You have to allocate enough cumulative space for the strings that you want to concatenate and you have to concatenate them in the allocated space.
To save you even more trouble, here's another problem:
finput=fopen(arguments[counter], "r");
...
while(!feof(finput))
feof() only works after at least one read from a file. This has been asked ans answered multiple times.
Try changing
for(counter=1; counter<n; ++n)
{
to
for(counter=1; counter<n; ++counter)
It appears the code loops infinitely, therefore it would exhaust the possible elements in your argument array causing a NULL pointer to be returned.

fopen c with multiple files

In my software I have to read multiple txt databases in a serial way, so I read the first, then I do something with the info I got from that file, than I open another one to write and so on.
Sometimes I got an error on an opening OR creation of a file, and then I got errors on all the following opening/creation, which uses different functions, different variables, different files.
So for example I call the function below, which uses two files, and I got an error "* error while opening file -%s- ..\n", then all the other fopen() in my code goes wrong!
This is an example of code for one single file:
FILE *filea;
if((filea=fopen(databaseTmp, "rb"))==NULL) {
printf("* error while opening file -%s- ..\n",databaseTmp);
fclose (filea);
printf("---------- createDatabaseBackup ----------\n");
return -1;
}
int emptyFolder=1;
FILE *fileb;
if((fileb=fopen(databaseBackup, "ab"))==NULL) {
printf("* error while opening file -%s- ..\n",databaseBackup);
fclose (fileb);
printf("---------- createDatabaseBackup ----------\n");
return -1;
}
else {
int i=0;
char c[500]="";
for (i=0;fgets(c,500,filea);i++) {
fprintf(fileb,"%s",c);
emptyFolder=0;
}
}
fclose(fileb);
fclose(filea);
There is an upper limit on the number of open handles for a given process. May be you have a handle leak in your program ?
Error while creating a file typically means you don't have access permission to the parent folder .
Those error log messages belong to your program . You can enhance it further. There is an errnum set by the os as fopen is essentially a system call. You can print that error number and get more info about your issue.
If fopen returned NULL, the file wasn't opened, so there's no point in trying to fclose it.
You should check the return value of fgets besides whether it is 0 or not. If it reads 500 characters and the buffer is not null-terminated, the fprintf will attempt to write more characters than is allocated for c

Issue on file existence in C

Here is my code which checks if the file exists :
#include<stdio.h>
#include<zlib.h>
#include<unistd.h>
#include<string.h>
int main(int argc, char *argv[])
{
char *path=NULL;
FILE *file = NULL;
char *fileSeparator = "/";
size_t size=100;
int index ;
printf("\nArgument count is = %d", argc);
if (argc <= 1)
{
printf("\nUsage: ./output filename1 filename2 ...");
printf("\n The program will display human readable information about the PNG file provided");
}
else if (argc > 1)
{
for (index = 1; index < argc;index++)
{
path = getcwd(path, size);
strcat(path, fileSeparator);
printf("\n File name entered is = %s", argv[index]);
strcat(path,argv[index]);
printf("\n The complete path of the file name is = %s", path);
if (access(path, F_OK) != -1)
{
printf("File does exist");
}
else
{
printf("File does not exist");
}
path=NULL;
}
}
return 0;
}
On running the command ./output test.txt test2.txt
The output is:
$ ./output test.txt test2.txt
Argument count is = 3
File name entered is = test.txt
The complete path of the file name is = /home/welcomeuser/test.txt
File does not exist
File name entered is = test2.txt
The complete path of the file name is = /home/welcomeuser/test2.txt
File does not exist
Now test.txt does exist on the system:
$ ls
assignment.c output.exe output.exe.stackdump test.txt
and yet test.txt is shown as a file not existing.
Please help me understand the issue here. Also, please feel free to post any suggestions to improve the code/avoid a bug.
Regards,
darkie
Just because the call to access() fails does not mean that the file does not exist. The call could fail for other reasons.
Use printf("error:%s\n", strerror(errno)); to print out the text of the error message.
Also you are still incorrectly appending to "path" received from getcwd as you were in your previous question. Even though it is not crashing, it is still not correct and could cause you problems... possibly even the problem you have now.
getcwd() allocates a buffer for your path, but that buffer is only sized to fit the path. you are appending to that buffer, going past the end. That's bad, you can't do that. It will cause problems, and occasionally crashes. you need to pause and understand how this getcwd function works and how to properly use it.
I strongly suggest allocating enough room to store the path via malloc() and fpathconf() (hint, PATH_MAX).
A non-standard way of allocating and assembling it would be asprintf().
Just be sure to free the resulting path when its no longer needed, and check every call that could possibly fail due to user typos for failure.
If using malloc(), always check for failure (the result being NULL).
Good luck with your assignment :)

Resources