I am facing a segmentation fault when I run the following program . I
am trying to make a multithreading program which performs 100 times :
Open the file.
Read the last line of the file (each line contains a number).
Add 3 to the number.
Append the new number at the end of the file.
Close the file.
The number of threads is specified by the user.
When I create 2 threads, this code runs correctly,
but when I try to create 1 or a number different from 2,
it shows segmentation fault.
I am using a semaphore for synchronization among threads.
Do you have any idea why this happens ?
Part of main:
for(i=0;i<NumberOfThreads;i++) {
if (pthread_create( pid[i], NULL, subthread, NULL ) != 0) {
fprintf(stderr, "pthread_create failed with i = %d. errno = %d, %s\n",i, errno, strerror(errno));
break;
}
}
for(i=0;i<NumberOfThreads;i++) {
pthread_join(*pid[i], NULL);
}
return 0;
}
void *subthread(void) {
int i ;
int temp ;
char ch;
int offset =0 ;
FILE * fd1 ;
FILE * fd2 ;
for(i=0 ;i<100;i++) {
sem_wait(&sem1);
fd1 = fopen (NameOfFile,"r");
fseek (fd1,-2,SEEK_END);
offset=-2;
while((ch=getc(fd1)) !='\n')
{
offset=offset-1;
fseek (fd1,offset,SEEK_END);
}
fscanf(fd1,"%d",&temp);
fclose(fd1);
fd2 = fopen (NameOfFile,"a");
temp=temp+3;
fprintf(fd2,"\n%d",temp);
printf("%d\n",temp);
fclose(fd2);
sem_post(&sem1);
}
pthread_exit(0);
}
This is just a part of the code.
When I run the code and give 1 thread as an input, it shows an segmentation fault. For 2 threads the execution is correct.
For more than 2 threads it shows again segmentation fault
When I try to debug, to see what is causing the segmentation fault, the log says that the function PTHREAD_CREATE causes it.
For pthread_create() the pointer passed as first argument must point to a valid location where pthread_create() writes thre thread id.
But as you have said in a comment, pid is defined as
pthread_t * pid[NumberOfThreads+1];
which is an array of pointers that do not point to a valid location initially. They might be NULL or undetermined depending on how the array is defined.
I would suggest you change the definition to
pthread_t pid[NumberOfThreads+1];
and call pthread_create(pid+i,....) or pthread_create(&pid[i],...); and use pid[i] instead of *pid[i] for other pthread_...() calls
Related
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.
I'm having an issue with being able to write to a file I've created globally, initialized in main (successfully), and writing to in a function used by multiple threads (on Linux).
#includes
FILE *f;
main(){
// Create threads successfully
f = fopen("fileName.txt", "w");
// Make sure the file was able to be created
if(f = NULL){
printf("Unable to create file");
exit(1);
}
// This much works, the check indicates the file was created
// successfully when I run it
while(1){
// loops for a while, getting input from user to direct threads
// When end is determined, waits for all the threads to finish,
// clears allocated memory, and closes file then returns
fclose(f);
return;
}
}
void *threadProcess(){
// Do stuff
// This printf works fine using the values i give the function, as is here
// The values are determined in 'Do stuff'
printf("%d trying to write \"%d BAL %d TIME %d.%06d %d.%06d\" to the file\n", cid, tmp->reqNum, balance, tmp->seconds, tmp->useconds, endTime.tv_sec, endTime.tv_usec);
fflush(stdout);
// There appears to be a Segmentation fault here
fprintf(f, "%d BAL %d TIME %d.%06d %d.%06d\n", tmp->reqNum, balance, tmp->seconds, tmp->useconds, endTime.tv_sec, endTime.tv_usec);
// Never gets here
}
What am I doing wrong here? As I said, the printf statement right before the fprintf statement works and outputs the correct stuff.
Am I wrong to assume that would ensure I don't have an pointer issues for fprintf?
Thanks
it was in my if(reqLog = NULL) check.... I was assigning not comparing. Sorry to have wasted your time haha. – tompon
So I have a mytee program (with much much less functionality). Trying to learn how to work with pipes / children / etc
(1) I do pipe
(2) Create the file(s)
(3) fork
(4) the parent does scanf to get the text
(5) sends the text to the pipe
(6) child receives it and writes it to files
-> #4 should be a loop until the user writes '.'
-> #6 should continue writing new lines, but somewhere there is a breakdown.
Some of the things that I think it might be:
1. Something is wrong with my permissions (but O_APPEND is there, and not sure what else I would need)
2. there may be a problem in parent do while loop, where it should send the msg to the pipe (fd[1])
3. #6 where I strongly think my problem lies. After the initial write it doesn, continue writing. I am not sure if I need to somehow keep track of the size of bytes already written, but if that was the case I would expect the last message to be there not the first.
I'm pretty much at a loss right now
I run it using
./mytee test1
Code:
ret = pipe (fd);
if (ret == -1)
{
perror ("pipe");
return 1;
}
for (i=0;i<argc-1;i++) {
if ((filefd[i] = open(argv[i+1], O_CREAT|O_TRUNC|O_WRONLY|O_APPEND, 0644)) < 0) {
perror(argv[i]); /* open failed */
return 1;
}
}
pid = fork();
if (pid==0) /* child */
{
int read_data;
do {
read_data = read(fd[0], buffer, sizeof(buffer));
for(i=0;i<argc;i++) {
write(filefd[i], buffer, read_data);
}
} while (read_data > 1);
for (i=0; i<argc; i++)
close(filefd[i]);
return 0;
}
else { /* parent */
char msg[20];
do{
scanf("%s",msg);
write(fd[1],msg,sizeof(msg));
}while (strcmp(msg,".")!=0);
while ((pid = wait(&status)) != -1)
fprintf(stderr, "process %d exits with %d\n", pid, WEXITSTATUS(status));
return 0;
}
Adding Output:
$ ./a.out test1
qwe
asd
zxc
.
^C
It doesn't exit properly. I think the child is stuck in the loop
And the contents of test1:
qwe
Working through this with the OP, reportedly the problem was unconditionally writing all 20 bytes of msg instead of just the NUL-terminated string contained within it. Suggested minimal fix: change
scanf("%s",msg);
write(fd[1],msg,sizeof(msg));
to
scanf("%19s",msg);
write(fd[1],msg,strlen(msg));
I see a couple of issues, which could potentially cause that behaviour.
Firstly, your loop condition doesn't look right. Currently it will terminate if a single byte is read. Change it to this:
while (read_data > 0);
The other issue I see is that you're writing to more files than you opened. Make sure you loop to argc-1, not argc:
for (i=0; i<argc-1; i++)
I'm implementing a history feature for a command line shell. I've implemented a circular array to hold to ten most recent commands. Each command is also labeled by an integer specifying which total command is. For Example, if 30 total commands were entered, the ten commands in the circular array would be numbered (30, 29, 28, 27,...,21).
If a user were to insert the command "r" followed by a number labeling one of the ten instructions then that instruction is supposed to run. I keep running into a seg fault when trying to ensure that a two word command is accepted properly. Can anyone help point out what the problem is.
int main(void)
{
char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
int background; /* equals 1 if a command is followed by '&' */
char *args[MAX_LINE/2+1];/* command line (of 80) has max of 40 arguments */
int position, count, rnum = 0;
char historyArray[10][MAX_LINE];
char *holder[MAX_LINE]={0};
while (1){ /* Program terminates normally inside setup */
background = 0;
printf("COMMAND->");
fflush(0);
setup(inputBuffer, args, &background); /* get next command */
position = (count % MOD_VAL);
strcpy(historyArray[position],args[0]);
if(!strcmp("rr",args[0]))
{
strcpy(historyArray[position],historyArray[((position-1)+MOD_VAL)%MOD_VAL]);
printf("%i",count);
printf("%c",'.');
printf("%c",' ');
printf("%s",historyArray[position]);
printf("%c",'\n');
strcpy(args[0],historyArray[position]);
}
else if(!strcmp("r",args[0])) //SEG FAULT OCCURING IN THIS ELSE-IF BLOCK!
{
//args[1] will hold given number
printf("%c",'\n');
printf("%s",args[0]);
printf("%s",args[1]);
printf("%s",args[2]);
printf("%c",'\n'); //PRINT STATEMENTS FOR DEBUGGING
strncpy(holder[0], args[2], MAX_LINE - 1); //SEG FAULT
rnum = atoi(args[1]);
strcpy(historyArray[position],historyArray[((position-(count-rnum))+MOD_VAL)%MOD_VAL]);
strcpy(args[0],historyArray[position]); //CHANGES VALUES OF args[1], args[2]
if(holder[0] != NULL)
{
strncpy(args[1],holder[0],MAX_LINE-1);
args[2] = NULL;
}
else
{
args[1] = NULL;
}
printf("%c",'\n');
printf("%s",args[0]);
printf("%s",args[1]);
printf("%s",args[2]);
printf("%c",'\n');
}
else if(!(strcmp("h",args[0]))||!(strcmp("history",args[0])))
{
int counter = 0;
while(counter < 10)
{
printf("%i",(count - counter));
printf("%c",'.');
printf("%c",' ');
printf("%s", historyArray[((position - counter + MOD_VAL)%MOD_VAL)]);
printf("%c",' ');
printf("%c",'\n');
counter ++;
if(counter > count)
break;
}
}
count++;
pid_t pid1; //Initialize pid_t variable to hold process identifier
pid1 = fork(); //Fork process and assign process identifier to "pid1"
if (pid1 == 0) //Child process
{
//Child process executes the command specified by the user and
//then quits.
execvp(args[0], args);
exit(0);
}
else //Parent process
{
if (background != 1)//Check for inclusion of '&' in command
{
wait(NULL); //Wait for child process to finish executing
}
}
/* the steps are:
(1) fork a child process using fork()
(2) the child process will invoke execvp()
(3) if background == 0, the parent will wait,
otherwise returns to the setup() function. */
}
}
Any assistance is appreciated!
-MATT
Here your args is the array of character pointers.
But strcpy requires two arguments - that should be array or character pointer to which memory allocated by malloc
But your strcpy(historyArray[position],args[0]); takes one argument as character pointer which will not be accepted.
so you can either change the args[] to args[][] or args[0] = malloc(some_no), segfault will be removed.
You note that the crash occurs on the line
else if(!strcmp("r",args[0]))
If I were you, I would load the core file in a debugger and see what the value of args[0] is when passed to strcmp().
I expect you have compiler warnings about type mismatch between char and char*. You declare args as char*. That means args[0] is a char, not a char*. To compare the single character, just use a character instead of strcmp():
else if ('r' != args[0])
Some notes on pitfalls with C's string handling:
strcmp() isn't safe with respect to array boundaries when its arguments are not correctly NUL-terminated
use strncmp() to provide a limit to the number of characters compared
although strncpy() guards against array boundaries, it does not guarantee to NUL-terminate the destination string
strcpy() does not respect array boundaries; it is your responsibility to ensure the destination array is large enough to receive the string being copied to it
You are missing to allocated memory the the char pointers held in args and holder.
So referring to those as pointers to 0-terminated character arrays ("strings") via the str*() family of functions, leads to undefined bahaviour, as the str*() function try to derefernce those pointers not point to valid memory.
I am studying mutexes and I am stuck in an exercise. For each file in a given directory, I have to create a thread to read it and display its contents (no problem if order is not correct).
So far, the threads are running this function:
void * reader_thread (void * arg)
{
char * file_path = (char*)arg;
FILE * f;
char temp[20];
int value;
f=fopen(file_path, "r");
printf("Opened %s.\n",file_path);
while (fscanf(f, "%s",temp)!=EOF)
if (!get_number (temp, &value)) /*Gets int value from given string (if numeric)*/
printf("Thread %lu -> %s: %d\n", pthread_self(), file_path, value );
fclose(f);
pthread_exit(NULL);
}
Being called by a function that receives a DIR pointer, previously created by opendir().
(I have omitted some error checking here to make it cleaner, but I get no error at all.)
int readfiles (DIR * dir, char * path)
{
struct dirent * temp = NULL;
char * file_path;
pthread_t thList [MAX_THREADS];
int nThreads=0, i;
memset(thList, 0, sizeof(pthread_t)*MAX_THREADS);
file_path=malloc((257+strlen(path))*sizeof(char));
while((temp = readdir (dir))!=NULL && nThreads<MAX_THREADS) /*Reads files from dir*/
{
if (temp->d_name[0] != '.') /*Ignores the ones beggining with '.'*/
{
get_file_path(path, temp->d_name, file_path); /*Computes rute (overwritten every iteration)*/
printf("Got %s.\n", file_path);
pthread_create(&thList[nThreads], NULL, reader_thread, (void * )file_path)
nThreads++;
}
}
printf("readdir: %s\n", strerror (errno )); /*Just in case*/
for (i=0; i<nThreads ; i++)
pthread_join(thList[i], NULL)
if (file_path)
free(file_path);
return 0;
}
My problem here is that, although paths are computed perfectly, the threads don't seem to receive the correct argument. They all read the same file. This is the output I get:
Got test/testB.
Got test/testA.
readdir: Success
Opened test/testA.
Thread 139976911939328 -> test/testA: 3536
Thread 139976911939328 -> test/testA: 37
Thread 139976911939328 -> test/testA: -38
Thread 139976911939328 -> test/testA: -985
Opened test/testA.
Thread 139976903546624 -> test/testA: 3536
Thread 139976903546624 -> test/testA: 37
Thread 139976903546624 -> test/testA: -38
Thread 139976903546624 -> test/testA: -985
If I join the threads before the next one begins, it works OK. So I assume there is a critical section somewhere, but I don't really know how to find it. I have tried mutexing the whole thread function:
void * reader_thread (void * arg)
{
pthread_mutex_lock(&mutex_file);
/*...*/
pthread_mutex_unlock(&mutex_file);
}
And also, mutexing the while loop in the second function. Even both at the same time. But it won't work in any way. By the way, mutex_file is a global variable, which is init'd by pthread_mutex_init() in main().
I would really appreciate a piece of advice with this, as I don't really know what I'm doing wrong. I would also appreciate some good reference or book, as mutexes and System V semaphores are feeling a bit difficult to me.
Thank you very much.
Well, you are passing exactly the same pointer as file path to both threads. As a result, they read file name from the same string and end up reading the same file. Actually, you get a little bit lucky here because in reality you have a race condition — you update the contents of the string pointer by file_path while firing up threads that read from that pointer, so you may end up with a thread reading that memory while it is being changed. What you have to do is allocate an argument for each thread separately (i.e. call malloc and related logic in your while loop), and then free those arguments once thread is exited.
Looks like you're using the same file_path buffer for all threads, just loading it over and over again with the next name. You need to allocate a new string for each thread, and have each thread delete the string after using it.
edit
Since you already have an array of threads, you could just make a parallel array of char[], each holding the filename for the corresponding thread. This would avoid malloc/free.