Getting wrong value for ID in pthreads - c

I'm trying to get my output to be
Starting Professor 1
Starting Professor 2
Starting Professor 3
...
but I never get "Starting Professor 1" when num_professors = 2. I thought making an array of ids would save the whole passing in of the address of id, but apparently not. There's about 70 other things I have to do for this project and having a roadblock on this simple thing (that probably takes a few seconds to fix) is quite frustrating to say the least. Thanks is greatly appreciated
void * professorFunc(void *p){
sem_wait(&workAssignment);
if(buffer == 0){
buffer++;
Professor *professor = (Professor*)p;
fprintf(stdout,"Starting Professor %d\n", *professor->id);
}
buffer = 0;
sem_post(&workAssignment);
pthread_exit(0);
}
int main(int argc, char ** argv){
//Semaphore intialization
buffer = 0;
if(sem_init(&workAssignment, 0, 1)){
printf("Could not initialize semaphore.\n");
exit(1);
}
//Creating threads
pthread_t professor[num_professors];
Professor *p;
int ids[num_professors];
int i;
p = malloc (sizeof (*p) * num_professors);
for(i = 0; i < num_professors; ++i){
ids[i] = i + 1;
p->id = &ids[i];
//printf("Id: %d\n", *p->id);
if(pthread_create(&professor[i], NULL, professorFunc, p) != 0){
perror("pthread_create");
exit(1);
}
//printf("yo I'm here after function now\n");
}
for(i = 0; i < num_professors; ++i){
if(pthread_join(professor[i], NULL) != 0){
perror("pthread_join");
exit(1);
}
}
free(p);
}

This line:
if(pthread_create(&professor[i], NULL, professorFunc, p) != 0){
should be:
if(pthread_create(&professor[i], NULL, professorFunc, &p[i]) != 0){

Related

How to fix a Segmentation Fault in pthread_create call

I am having an issue with my current code. I am working on a project where I am using threads to read a group of files from the terminal and tell how many lines there are in the individual and total grouping of files. My question is that when I run the code I get a core dump and when I run my code through gdb I get a segmentation fault at the pthread_create call. Is it because of my implementation or is it due to something else in my code?
#define NUM_THREADS 12
struct thread_data{
char *thread_id;
int count;
};
struct thread_data thread_data_array[NUM_THREADS];
void* filecount(void * thread_arg){
char thread_id;
int count;
struct thread_data *thread;
thread = (struct thread_data *) thread_arg;
thread_id = *thread->thread_id;
count = thread->count;
FILE *fp = fopen(&thread_id, "r");
if (fp == NULL) {
fprintf(stderr, "Cannot open %s\n", thread_id);
exit(-1);
}
for (char c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n')
count++;
fclose(fp);
pthread_exit(NULL);
}
int main(int argc, char *argv[]){
if (argc == 1)
return 0;
pthread_t threads[argc];
int t, total_count, count;
total_count = 0;
for(t=1; t<argc; t++){
thread_data_array[t].thread_id = argv[t];
thread_data_array[t].count = count;
printf("Creating thread for file: %s",thread_data_array[t].thread_id);
///This is the line in question///
pthread_create(&threads[t], NULL,filecount,(void *) &thread_data_array[t]);
printf("File name: %s --- line count: %d", thread_data_array[t].thread_id, total_count);
total_count += thread_data_array[t].count;
}
printf("Total line count: %d", total_count);
pthread_exit(NULL);
}
To summarize some of the comments:
This
char thread_id;
thread_id = *thread->thread_id;
will give you the first character of the filename. So while &thread_id is the correct type (char *) for the first argument of fopen, its not a pointer to a null terminating string. This is undefined behaviour.
In
thread_data_array[t].count = count;
count is uninitialized, and its value is indeterminate. This is undefined behaviour.
You need to wait for each thread to finish before you use its result. pthread_join is the function to use here.
getc (fgetc) returns type int, which allows for the check against EOF. Narrowing to char removes the ability to properly test for EOF.
thread_data_array should match the threads array in size.
Here is a refactored program:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
struct thread_data {
char *thread_id;
int count;
};
void *filecount(void *thread_arg){
struct thread_data *arg = thread_arg;
FILE *fp = fopen(arg->thread_id, "r");
if (fp == NULL) {
fprintf(stderr, "Cannot open %s\n", arg->thread_id);
pthread_exit(NULL);
}
for (int c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n')
arg->count++;
fclose(fp);
return NULL;
}
int main(int argc, char *argv[]){
if (argc == 1)
return 0;
argv++;
argc--;
pthread_t threads[argc];
struct thread_data thread_data_array[argc];
int total_count = 0;
for (int i = 0; i < argc; i++) {
thread_data_array[i].thread_id = argv[i];
thread_data_array[i].count = 0;
pthread_create(&threads[i], NULL, filecount,(void *) &thread_data_array[i]);
}
for (int i = 0; i < argc; i++) {
pthread_join(threads[i], NULL);
total_count += thread_data_array[i].count;
}
printf("Total line count: %d\n", total_count);
}

Getting core dumps when freeing dynamic string array

I am trying to create a shell that takes user input and can execute Linux and built-in commands, and up until this point everything has been fine. My problem is that my function for executing piping commands sometimes core dumps. I know that it is core dumping when I'm iterating through the char** array to free each index, but it only core dumps every now and again.
Here is my function with some debug print statements.
int getCommand(int index, char** commands, char **args, int size){
int i = 0;
for(i; i < size && args[index] != NULL && strcmp(args[index],"|"); i++{
commands[i] = strdup(args[index]);
index++;
}
if(i < size)
commands[i] = NULL;
if(index < size && args[index] != NULL && !strcmp(args[index],"|"))
index++;
return index;
}
void pipe(char **args, int size, int numOfPipes){
char **commands = malloc(size*sizeof(char**));
int index = 0;
int new_fd[2], old_fd[2], status;
pid_t pid;
for(int i = 0; i < (numOfPipes+1); i++){
index = getCommand(index, commands, args, size);
if(pipe(new_fd[2] == -1){
printf("Pipe failed\n");
exit(1);
}
else if((pid = fork()) < 0){
printf("Fork failed\n");
exit(1);
}
else if(pid == 0){
if(i > 0){
dup2(old_fd[0],0);
close(old_fd[1]);
}
if(i < numOfPipes){
dup2(new_fd[1],1);
close(new_fd[0]);
}
if(execvp(*commands,commands) < 0){
printf("Command could not be executed.");
exit(1);
}
}
else{
close(old_fd[0]);
close(old_fd[1]);
wait(&status);
old_fd[0] = new_fd[0];
old_fd[1] = new_fd[1];
}
printf("Free strings\n");
/* Here is where it core dumps */
for(int i = 0; i < size; i++){
printf("%d\n",i);
free(commands[i]);
}
printf("Freeing pointer\n");
free(commands);
}
Can anyone help me see where I am going wrong?
I think that there are two problems :
because of the condition in the for-loop in getCommand, strdup is not guaranteed to be called size times, and therefore not all elements of the array commands will be initialized.
I suggest that you check if the elements aren't NULL before freeing them :
for(int i = 0; i < size; i++){
if (command[i] != NULL) {
printf("%d\n",i);
free(commands[i]);
}
}
2.
Because of the for-loop in the pipe function, getCommand is being called numOfPipes times and possibly allocating new memory every time for the command array elements , without freeing the previous allocated memory.
I suggest you check and free the memory before callinggetCommand (or strdup)

C Language- freeing memory after using strtok to build char**

and sorry for the title I couldn't think of a better way to phrase it.
so I have a C assignment working with fork and exec.
I have three programs called ps, echo and history all of them take different arguments. The final program is called shell and it takes in commands from stdin and calls for exec upon taking a proper command.
example:
ps -a
echo Hello World
history 1.txt
once it reads a line and find it's a valid command it makes a child process and calls for exec.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
const int MAX_LINE = 100;
const char *HISTORY = "./history";
const char *PS = "./ps";
const char *ECHO = "./echo";
void call_cmd(int cmd, char *const argv[]);
/* main function */
int main(int argc, char** argv)
{
FILE * out;
char line[MAX_LINE], line_print[MAX_LINE], seps[] = " \n", rm[80];
char *first, *tmp, ** params;
pid_t pid;
int cmd = -1, i = 0,j= 0;
if (argc != 2)
{
printf("Invalid arguments");
return EXIT_FAILURE;
}
out = fopen(argv[1],"w");
if (out == NULL)
{
perror("Couldn't open file to write");
return EXIT_FAILURE;
}
while(fgets(line,sizeof(line),stdin) != NULL)
{
strcpy(line_print,line);
params = (char**) malloc(sizeof(char*));
tmp = strtok(line,seps);
while (tmp != NULL)
{
if(i != 0)
params = (char**) realloc(params,sizeof(char*) * (i + 1));
params[i] = tmp;
j++;
tmp = strtok(NULL,seps);
i++;
}
first = params[0];
if (strcmp("exit",first) == 0)
{
sprintf(rm,"rm %s",argv[1]);
system(rm);
exit(0);
}
if(strcmp("echo",first) == 0)
cmd = 0;
if(strcmp("history",first) == 0)
cmd = 1;
if(strcmp("ps",first) == 0)
cmd = 2;
if(cmd == -1){
perror("\nInvalid Command\n");
}
if(cmd >= 0)
{
fprintf(out,"%s",line_print);
pid = fork();
if (pid == -1)
{
perror("Error Creating Child");
return EXIT_FAILURE;
}
if(pid == 0)
{
call_cmd(cmd,params);
exit(0);
}
}
for (i = 0; i < j ; i++)
free(params[i]);
free(params);
i = j = 0;
cmd = -1;
}
fclose(out);
return EXIT_SUCCESS;
}
void call_cmd(int cmd, char *const argv[])
{
switch(cmd)
{
case 0:
execv(ECHO, argv);
break;
case 1:
execv(HISTORY, argv);
break;
default:
execv(PS, argv);
break;
}
}
that is my code so far, it behaves in a weird way causing segmentation faults,
I'm pretty sure it's because of the way I split the parameters and free them.
example output:
*** Error in `./shell': double free or corruption (out): 0x00007ffe58f1a630 ***
Parent Id: 1928
Aborted (core dumped)
so I keep editing the for loop
for (i = 0; i < j ; i++)
free(params[i]);
all that does is just jump from double free to segmentation faults or I write a command like ps or history and it does nothing, so I must be doing something but I'm truly lost been trying to fix it for two days with, so if you see what I did wrong please point it out.
Thank you.
strtok parses a string in-place so you should not free the individual results. They are portions of the original string. You can use the POSIX function strdup to make copies that can be free'd, and will persist beyond the life of the original buffer contents.
You should add
params[0] = NULL;
right after the initial malloc (or use calloc) otherwise you'll be using an unitialized pointer if the line is empty. Then at the end
free(params);
you don't need to free any of params[i] since those are pointers into the local line[] buffer.

IO redirection and buffer issues, fflush and c

for my class we are to implement a shell with output redirection. I have the output redirection working, except my first command is always corrupted see:
$ echo this doesn't work
H<#?4echo
No such file or directory
$ echo this does work
this does work
but every command afterwards seems fine. What technique do I use to find the bug that is causing this problem?
I think it has something to do with not fflushing properly. I sprinkled it around my code (which was stupid) to see if it would help during the loop but it did not. I've also tried printing out my OrderedIds list which is just a list of commands to check if I could find H<#?4 anywhere, but even when I initialized it, it did not work.
Thanks for your help.
#define LENGTH 1000
#define MAXCMD 11
#define MAX_STR_LEN 20
void init(char *temp);
void clean(char **orderedIds);
void init_pid(int *temp);
void reap(int *temp,int ret_status);
void jobs(int *pid_list, char **orderedIds);
int ioRedir(char **orderedIds);
void reap(int *temp,int ret_status){//chainsaws all zombies
int a;
for (a=0; a<LENGTH; a++ ){
waitpid(temp[a],&ret_status,WNOHANG) == temp[a];
}
}
void init(char *temp){//Function to initialize/reset the cmd array
int i;
for(i=0; i<LENGTH; i++){
temp[i] = 0;
}
}
void init_pid(int *temp){//Function to initialize/reset the pid list
int i;
for(i=0; i<LENGTH; i++){
temp[i] = -777;
}
}
void clean(char **orderedIds){//garbage collection
int i;
for(i=0; i<MAXCMD; i++){
free(orderedIds[i]);
}
free(orderedIds);
}
void jobs(int *pid_list, char **orderedIds){//function to check for background proccesses
printf("Jobs:\n");
int y;
for(y=0; y<LENGTH; y++){
if(kill(pid_list[y], 0) == 0){
printf("%d\n", pid_list[y]);
}
}
clean(orderedIds);
printf("$ ");
}
int ioRedir(char **orderedIds){
int i;
for ( i = 0; i<MAXCMD; i++){
if(orderedIds[i] == NULL){
return -1;
}
if(strcmp(orderedIds[i],">")==0){
return (i+1);
}
}
}
int main (int argc, char *argv[], char *envp[])
{
char temp[LENGTH];
char * tok;
char c = '\0';
int saved_stdout;
int pid_list[LENGTH];
int ret_status;
int numFile;
int pid_counter = 0;
int outputfd = -1;
char outputFile[MAX_STR_LEN];
pid_t pid;
printf("$ ");
int i, j, y, background= 0;
init_pid(pid_list);
while(c !=EOF) { //while not ^D // Source: LinuxGazzette Ramankutty
outputfd = -1;
fflush(0);
c = getchar();
if(c=='\n'){ //entered command
reap(pid_list, ret_status);
char **orderedIds = malloc(MAXCMD * sizeof(char*));
for (i=0; i<MAXCMD; i++){
orderedIds[i] = malloc(MAXCMD * sizeof(char*));
}
int k=0;
tok = strtok(temp, " \n\t\r");
while (tok !=NULL){
strcpy(orderedIds[k], tok);
k++;
tok = strtok (NULL, " \n\t\r");
}
orderedIds[k] = NULL; //END with NULL
init(temp); //initialize the array
if(orderedIds[0] ==NULL){
printf("\n$ ");
continue;
}
numFile = ioRedir(orderedIds);
if(strcmp(orderedIds[0],"exit")==0){// if exit
printf("now exiting...\n");
break;
}
if(strcmp(orderedIds[k-1], "&")==0){//if background
orderedIds[k-1] = NULL;
background = 1;
}else background = 0;
if(strcmp(orderedIds[0], "jobs") == 0){//if jobs command
jobs(pid_list, orderedIds);
continue;
}
if(strcmp(orderedIds[0], "cd") == 0){ //if change directory command
chdir(orderedIds[1]);
printf("$ ");
continue;
}
pid = fork();
if (pid!=0 && background == 1)
{
//go to end of list in pid and put it in
pid_list[pid_counter] = pid;
pid_counter++;
printf("To the background: %d\n", pid);
} else if (pid==0 && background == 1) {
fclose(stdin); //close child's stdin
fopen("/dev/null", "r"); //open a new stdin that is always empty.
if(execvp(orderedIds[0], orderedIds)){
printf("%s\n", orderedIds[0]);
puts(strerror(errno));
exit(127);
}
}
if (pid != 0 && !background){
//printf("Waiting for child (%d)\n", pid);
fflush(0);
pid = wait(&ret_status);
} else if (pid == 0 && !background) {
if(numFile > 0){
strncpy(outputFile, orderedIds[numFile], strlen(orderedIds[numFile]));
numFile = 0;
//open the output file
outputfd = open(outputFile, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRGRP | S_IROTH);
if (outputfd < 0) {
exit(EXIT_FAILURE);
}
//close STDOUT
if(close(STDOUT_FILENO) < 0 ){
perror("close(2) file: STDOUT_FILENO");
close(outputfd);
exit(EXIT_FAILURE);
}
//use dup to rerout the output
if(saved_stdout = dup(outputfd) != STDOUT_FILENO){
perror("dup(2)");
close(outputfd);
exit(EXIT_FAILURE);
}
close(outputfd);
}
if (execvp(orderedIds[0], orderedIds)){
printf("%s\n", orderedIds[0]);
puts(strerror(errno));
exit(127);
}
}
dup2(saved_stdout,outputfd);
clean(orderedIds);
fflush(0);
printf("$ ");
} else {
strncat(temp, &c, 1);
}
}
fflush(0);
return 0;
}
The reason for the garbage is that you never initialized temp to an empty string at the beginning of main(). You call init(temp) after processing each command.
There are lots of other problems in your code:
orderedIds[i] = malloc(MAXCMD * sizeof(char*));
Since orderedIds[i] is an array of char, not char*, you should multiply the size by sizeof(char). Also, it's not clear why you're using MAXCMD as the size -- on the previous line this was the maximum number of words on a line, not the number of characters in a word.
strcpy(orderedIds[k], tok);
You should use strncpy() to ensure that you don't copy more than the size of orderedIds[k].
Another option would be not to preallocate all the orderedIds[i] in the first place. Instead of using strcpy(), use strdup() and assign this to orderedIds[k]; if you do this, you have to remember to free() all these strings.
A third option is not to copy the strings at all. Just assign the pointers returned by strtok() to orderedIds[k]. But in this case you mustn't call init(tmp) until after you've forked.
strncpy(outputFile, orderedIds[numFile], strlen(orderedIds[numFile]));
The limit should be the size of outputFile, not the length of orderedIds[numFile]. strncpy() will never copy more than the length of the source, you need to tell it the maximum size of the destination to prevent a buffer overflow.
outputfd = open(outputFile, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRGRP | S_IROTH);
if (outputfd < 0) {
exit(EXIT_FAILURE);
}
You should call perror() to report the reason that open() failed.
puts(strerror(errno));
Call perror(), like you do elsewhere.

Execl Returns Bad Address

I would really love some debugging help in this one. I've been working on this since the morning and its 4am. (I'm suppose to deliver this in 7 hours [11am])
Everything in main.c works but when I create some child processes to run compute.c's compiled file with execl it doesnt do it and sends an error of "Bad Address".
I've attached 3 pastebin links with main.c and compute.c and a txt file containing the tables I mention below.
The program is suppose to read 2 tables with integers from a file called pinakes.txt and then by using POSIX's shared memory API to place those tables in shared memory and create processes to calculate a 'row * column' sum from them and place that sum in another table.
sum += A[row][i] * B[i][column] = C[row][column]
Everything until the line below from main.c should work properly (I debugged it numerous times).
ppid = getpid();
main.c http://pastebin.com/iMCefaLZ
compute.c http://pastebin.com/Ejp214Up
pinakes.txt http://pastebin.com/h8yKXFvv
compile and then run
./main pinakes.txt
main.c
188 lines of code
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <errno.h>
int pinA_X = 0, pinA_Y = 0, pinB_X=0, pinB_Y=0;
int pinA[10][10], pinB[10][10], pinC[10][10];
main(int argc, char *argv[]){
int pid, ppid;
FILE *stream;
// general variables
int i, c, j, rc, converted, lines = 0;
//flags
int flagV=0, flagW=0, flagX=0, flagY=0, flagZ=0;
//shared memory
int dumpedArray[101];
int size = sizeof(dumpedArray);
int sid1 = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
int sid2 = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
int sid3 = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
int* shared_A = (int*) shmat(sid1, NULL, 0);
int* shared_B = (int*) shmat(sid2, NULL, 0);
int* shared_C = (int*) shmat(sid3, NULL, 0);
if(argc!=2){
printf("wrong number of arguments\n");
return -1;
}else{
stream = fopen(argv[1] , "r");
while((c = getc(stream))!= EOF){
if(flagZ == 0){
if(flagX == 1){pinA_X = c - 48;flagX = 0;}
if(c == 88){flagX = 1;}
if(flagY == 1){pinA_Y = c - 48;flagY = 0;}
if(c == 89){flagY = 1;}
if(c == 90){flagZ = 1;}
}else if(flagZ == 1){
if(flagX == 1){pinB_X = c - 48;flagX = 0;}
if(c == 88){flagX = 1;}
if(flagY == 1){pinB_Y = c - 48;flagY = 0;}
if(c == 89){flagY = 1;}
}
}
fclose(stream);
printf("pinA[%d][%d] * pinB[%d][%d] = C[%d][%d]\n\n", pinA_X, pinA_Y, pinB_X, pinB_Y, pinA_X, pinB_Y);
// get A
stream = fopen(argv[1] , "r");
i=0;j=0;
while((c = getc(stream))!= EOF){
if(i <= pinA_X && j <= pinA_Y){
if(flagW == 0){
if(c == 87){
flagW = 1;
}
}else{
if(c > 47 && c < 58){
pinA[i][j] = c - 48;
j++;
}
if(c == 13){
j=0;
i++;
}
}
}
}
fclose(stream);
// get B
stream = fopen(argv[1] , "r");
i=0;j=0;
while((c = getc(stream))!= EOF){
if(i <= pinB_X && j <= pinB_Y){
if(flagV == 0){
if(c == 86){
flagV = 1;
}
}else{
if(c > 47 && c < 58){
pinB[i][j] = c - 48;
j++;
}
if(c == 13){
j=0;
i++;
}
}
}
}
fclose(stream);
// print A
printf("A={\n");
for(j=0; j<pinA_X;j++){
for(i=0;i<pinA_Y;i++){
printf(" %d", pinA[j][i]);
}
printf("\n");
}
printf("}\n\n");
// print B
printf("B={\n");
for(j=0; j<pinB_X;j++){
for(i=0;i<pinB_Y;i++){
printf(" %d", pinB[j][i]);
}
printf("\n");
}
printf("}\n");
// Save pinA to shared Memory
converted = 0;
for(i=0;i<10;i++){
for(j=0;j<10;j++){
converted = (i * 10) + j;
shared_A[converted] = pinA[i][j];
}
}
// Save pinA to shared Memory
converted = 0;
for(i=0;i<10;i++){
for(j=0;j<10;j++){
converted = (i * 10) + j;
shared_B[converted] = pinB[i][j];
}
}
// Push size of arrays in shared memory
shared_A[100] = pinA_X;
shared_A[101] = pinA_Y;
shared_B[100] = pinB_X;
shared_B[101] = pinB_Y;
ppid = getpid();
for(i=0; i<pinA_X; i++){
for(j=0; j<pinB_Y; j++){
if(ppid == getpid()){
pid = fork();
if(pid==0){
if(execl("./compute", "compute", i, j, sid1, sid2, sid3, NULL) == -1){
printf("error exec\n");
printf("Error opening file: %s\n", strerror(errno));
};
}else if(pid<0){
printf("\nDen egine h fork!\n");
}else{
wait(0);
}
}
}
}
//print C
converted = 0;
printf("C={\n");
for(i=0;i<10;i++){
for(j=0;j<10;j++){
converted = (i * 10) + j;
pinC[i][j] = shared_C[converted];
printf(" %d", pinC[i][j]);
}
printf("\n");
}
printf("}\n");
}
}
Neither compute.c nor pintakes.txt is directly relevant to answering this question.
The bad address problem arises because you run:
for(i=0; i<pinA_X; i++){
for(j=0; j<pinB_Y; j++){
if(ppid == getpid()){
pid = fork();
if(pid==0){
if(execl("./compute", "compute", i, j, sid1, sid2, sid3, NULL) == -1){
The arguments to execl() must be strings; i and j are manifestly not strings (and sid1, sid2 and sid3 are the identifiers for three chunks of shared memory).
Convert those values to strings and try again.
Your program creates the shared memory with IPC_PRIVATE, so your code in compute.c (which is executed via execl() is going to be hard to make work. You may get away with transferring the shared memory IDs like that; I'm not sure.
I think I'd be using a single shared memory segment.
It also looked like your reading code is going to read the same data into the two arrays - but I may have been misreading it.
Finally, your PasteBin examples expire in 23 hours. That limits the usefulness of your question. You should really transfer the data into the question - with, I suggest, no tabs and tabstops set at 4 rather than 8. (Or use more functions to prevent such deep indentation.)
You are passing ints to execl, those should all be 0-terminated strings. Also, the final NULL must be cast to Char*.

Resources