E.Y. E.Y. - 1 month ago 9
C Question

Segmentation fault (core dumped) on Virtual Ubuntu64bit

I am trying to learn multithreaded and multiprocessed programming. I am very new to both multithreaded/processed programing and Ubuntu environment. I worked on the code below for a good 10 hours and fixed all errors and warnings. I started to code this with xCode and it is running perfectly and does exactly what I want it to do without any warnings or errors on that environment. But when try to compile and run on Ubuntu I get a segmentation fault(core dumped) I couldn't understand which part of the code resulting in this error. Any ideas on which part might cause the error? or why I am getting that? As I remember Linux does not have a core? Thank you so much in advance!

My data files have the following format: there can be any number of course documents in the folder and each course document may have a different number of lines. However, number of grades is fixed to three. So each file will have something like;
100 95 93
100 88 75
95 94 71
100 88 71

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <err.h>
#include <sys/types.h>
#include <dirent.h>
#include <regex.h>
#include <string.h>
#include <stdlib.h>

int pid, i, rc, pid1, counter;
char* iterator[500];
char* file[500];
enum {

WALK_OK = 0,
WALK_BADPATTERN,
WALK_BADOPEN,
};

int walker(const char *dir, const char *pattern)
{
struct dirent *entry;
regex_t reg;
DIR *d;
counter=0;
if (regcomp(&reg, pattern, REG_EXTENDED | REG_NOSUB))
return WALK_BADPATTERN;
if (!(d = opendir(dir)))
return WALK_BADOPEN;
while ((entry = (readdir(d))) ){
if (!regexec(&reg, entry->d_name, 0, NULL, 0)){
puts(entry->d_name);
file[counter]=entry->d_name;
counter=counter+1;}
}
closedir(d);
regfree(&reg);
return counter;
}


void* project_statistics(int i){

FILE* f;
// size_t len;
char* line;
int read[3];
int arr[1000];
int p, m, fnl;

int counter2=0;
f=fopen(iterator[i], "r");

if (f==NULL) {
err(1, "%s", iterator[i]);

}
while((line=fgets((char*)read,sizeof(read),f))){

sscanf(line, "%d %d %d",&p, &m, &fnl);
arr[counter2]= p;
counter2++;
}

int *firstHalf = malloc((counter2) * sizeof(int));
memcpy(firstHalf, arr, (counter2) * sizeof(int));

//sort array;
int k, l, tmp;

for (k = 1; k < counter2; k++) {

l = k;

while (l > 0 && firstHalf[l - 1] > firstHalf[l]) {

tmp = firstHalf[l];
firstHalf[l] = firstHalf[l- 1];
firstHalf[l- 1] = tmp;
l--;

}

}

printf("course %d project median: %d, project min: %d, project max: %d\n", i+1, firstHalf[counter2/2], firstHalf[0],firstHalf[counter2-1]);

if(!feof(f)){
err(1, "getIn");
}
pthread_exit(NULL);

}

void* midterm_statistics(int i){

FILE* f;
int read[3];
char* line;
int arr2[1000];

int p, m, fnl;

int counter2=0;

f=fopen(iterator[i], "r");

if (f==NULL) {
err(1, "%s", iterator[i]);

}

while((line=fgets((char*)read,sizeof(read),f))){

sscanf(line, "%d %d %d",&p, &m, &fnl);
arr2[counter2]=m;
counter2++;
}
int *firstHalf = malloc((counter2) * sizeof(int));
memcpy(firstHalf, arr2, (counter2) * sizeof(int));

//sort array;
int k, l, tmp;

for (k = 1; k < counter2; k++) {

l = k;

while (l > 0 && firstHalf[l - 1] > firstHalf[l]) {

tmp = firstHalf[l];
firstHalf[l] = firstHalf[l- 1];
firstHalf[l- 1] = tmp;
l--;

}

}

printf("course %d project median: %d, project min: %d, project max: %d\n", i+1, firstHalf[counter2/2], firstHalf[0],firstHalf[counter2-1]);
if(!feof(f)){
err(1, "getIn");
}
pthread_exit(NULL);

}

void* final_statistics(int i){

FILE* f;
char* line;
int arr3[1000];
int read[3];
int p, m, fnl;

int counter2=0;

f=fopen(iterator[i], "r");

if (f==NULL) {
err(1, "%s", iterator[i]);

}

while((line=fgets((char*)read,sizeof(read),f))){

sscanf(line, "%d %d %d",&p, &m, &fnl);
arr3[counter2]=fnl;
counter2++;
}

int *firstHalf = malloc((counter2) * sizeof(int));
memcpy(firstHalf, arr3, (counter2) * sizeof(int));

//sort array;
int k, l, tmp;

for (k = 1; k < counter2; k++) {

l = k;

while (l > 0 && firstHalf[l - 1] > firstHalf[l]) {

tmp = firstHalf[l];
firstHalf[l] = firstHalf[l- 1];
firstHalf[l- 1] = tmp;
l--;

}

}

printf("course %d project median: %d, project min: %d, project max: %d\n", i+1, firstHalf[counter2/2], firstHalf[0],firstHalf[counter2-1]);

if(!feof(f)){
err(1, "getIn");
}
pthread_exit(NULL);

}



int main(int argc, const char * argv[]) {

char krkt[500];

int counter1=walker("/home/ey/Desktop/sampleFolder/", ".\\.txt");
for (i=0; i<counter1; i++) {
strcpy(krkt, "/home/ey/Desktop/sampleFolder/");
strcat(krkt, file[i]);
iterator[i]=strdup(krkt);
printf("%s",iterator[i]);
}

printf("\nMaster is starting\n");

pthread_t tid1[counter1], tid2[counter1], tid3[counter1];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
printf("\nslave1 start\n");
printf("\n~Project Statistics~\n");

sleep(2);
for (i=0; i<counter1; i++) {

rc=pthread_create(&tid1[i], &attr, (void*)*project_statistics,(void*)(intptr_t)i);

}

sleep(2);

printf("\nslave1 done\n");


printf("\nslave2 start\n");
printf("\n~Midterm Statistics~\n");

pid=fork();
sleep(2);
if (pid==0) {
for (i=0; i<counter1; i++) {

rc=pthread_create(&tid2[i], &attr,(void*)*midterm_statistics, (void*)(intptr_t)i);
}

sleep(2);
printf("\nslave2 done\n");
printf("\nslave3 start\n");
printf("\n~Final Statistics~\n");
}
sleep(2);

pid1=fork();
sleep(2);

if ((pid1==0)&&(pid==0)) {

for (i=0; i<counter1; i++) {

rc=pthread_create(&tid3[i], &attr, (void*)*final_statistics, (void*)(intptr_t)i);
}

sleep(2);
printf("\nslave3 done\n");
printf("\nMaster is done\n");
}




sleep(1);
pthread_attr_destroy(&attr);
pthread_exit(NULL);

}

Answer

In main, your strcat is faulting.

The source address is file[i]. file is a global array of char * pointers. But, it is [apparently] never initialized to anything.

So the strcat call will have a second argument of NULL, which causes the segfault.

This might occur if walker returns a non-zero value, which it would if the directory does not exist (i.e. the return is WALK_BADOPEN). This might explain why it works on one system but not another (i.e. the directory exists on one but not the other).

So, walker is using returning an error code, but main is using this return value as a count. This logic is incorrect. I believe you'll need to change the return value of walker or have main get the count a different way.

The easy way to fix this is to make the error codes negative values and have main check for this. Then, walker can return the count correctly.

So, if the directory does not exist, the return value is 2. The loop in main will fault on file[0] because nothing in file has been set to anything.


UPDATE:

But for this time since I know the directory does exist, could I be trying to open it in the wrong way?

There is no "wrong" way to use opendir--it either opens or fails, which you already handle.

But, inside walker, you can't rely upon the d_name value from loop iteration to iteration, so, you have to use strdup.

Change:

file[counter] = entry->d_name;

Into:

file[counter] = strdup(entry->d_name);

Also, you should limit check against the maximum for file (e.g. currently only 500)


UPDATE #2:

In your thread functions, you were doing fgets into read [not a good choice because of libc's read function]. But, it was:

int read[3];

So, the line buffer was only 12 bytes long. This could cause the fgets to read a line as two partially split lines. This might cause the arr array to overflow

I changed this to:

char buf[1000];

I've combined the replicated code of the thread functions to a common one.

Note that firstHalf was allocated but never freed. So, it was "leaking". I added a free call for it.

Also note that there was no fclose(f) which could cause an fopen to return NULL (i.e. another source for segfault).

I've also reworked the thread join and fork logic and added waitpid. Also note the addition of exit(0) to the fork's child code.

As I was trying to understand things, I was simplifying things, so the following is a fair rework, and may seem a bit "alien" at first [please pardon the gratuitous style cleanup]:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <err.h>
#include <sys/types.h>
#include <dirent.h>
#include <regex.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>

#if 1
#define MYDIR   "/home/ey/Desktop/sampleFolder/"
#else
#define MYDIR   "/tmp/data/"
#endif

#define dbgprt(_fmt...) \
    do { \
        if (opt_dbg) \
            printf(_fmt); \
    } while (0)

int opt_dbg;

int pid;
int i;
int rc;
int pid1;
int counter;

char *iterator[500];
char *file[500];

enum {
    WALK_OK = 0,
    WALK_BADPATTERN = -1,
    WALK_BADOPEN = -2,
};

int
walker(const char *dir,const char *pattern)
{
    struct dirent *entry;
    regex_t reg;
    DIR *d;

    counter = 0;
    if (regcomp(&reg,pattern,REG_EXTENDED | REG_NOSUB))
        return WALK_BADPATTERN;

    d = opendir(dir);
    if (d == NULL)
        return WALK_BADOPEN;

    while (1) {
        entry = readdir(d);
        if (entry == NULL)
            break;

        if (!regexec(&reg,entry->d_name,0,NULL,0)) {
            puts(entry->d_name);
            file[counter] = strdup(entry->d_name);
            counter = counter + 1;
        }
    }

    closedir(d);
    regfree(&reg);
    return counter;
}

void *
thread_common(void *arg,int column)
{
    intptr_t i = (intptr_t) arg;
    FILE *f;

    // size_t len;
    char *line;
    int data[3];
    char buf[1000];
    int arr[1000];

    int counter2 = 0;

    f = fopen(iterator[i],"r");
    if (f == NULL) {
        err(1,"%s",iterator[i]);
    }

    dbgprt("DEBUG reading ...\n");
    while (1) {
        line = fgets(buf,sizeof(buf),f);
        if (line == NULL)
            break;

        sscanf(line,"%d %d %d",&data[0],&data[1],&data[2]);
        arr[counter2] = data[column];

        counter2++;
        dbgprt("DEBUG line %d %s\n",counter2,iterator[i]);
        if (counter2 >= 1000) {
            printf("overflow %s\n",iterator[i]);
            exit(1);
        }
    }

    if (!feof(f)) {
        err(1,"getIn");
    }

    fclose(f);

    int *firstHalf = malloc((counter2) * sizeof(int));
    memcpy(firstHalf,arr,(counter2) * sizeof(int));

    // sort array;
    int k,
     l,
     tmp;

    dbgprt("DEBUG sorting ...\n");
    for (k = 1; k < counter2; k++) {
        for (l = k;  (l > 0) && (firstHalf[l - 1] > firstHalf[l]);  l--) {
            tmp = firstHalf[l];
            firstHalf[l] = firstHalf[l - 1];
            firstHalf[l - 1] = tmp;
            l--;
        }
    }

    printf("course %ld project median: %d, project min: %d, project max: %d\n",
        i + 1,firstHalf[counter2 / 2],firstHalf[0],firstHalf[counter2 - 1]);

    free(firstHalf);

    return (void *) 0;
}

void *
project_statistics(void *arg)
{

    return thread_common(arg,0);
}

void *
midterm_statistics(void *arg)
{

    return thread_common(arg,1);
}

void *
final_statistics(void *arg)
{

    return thread_common(arg,2);
}

int
main(int argc,char **argv)
{
    intptr_t i;
    char *cp;
    char krkt[500];

    --argc;
    ++argv;

    for (;  argc > 0;  --argc, ++argv) {
        cp = *argv;
        if (*cp != '-')
            break;

        switch (cp[1]) {
        case 'd':
            opt_dbg = 1;
            break;

        default:
            break;
        }
    }

    int counter1 = walker(MYDIR,".\\.txt");
    dbgprt("main: walker returned %d\n",counter1);
    if (counter1 <= 0)
        exit(1);

    for (i = 0; i < counter1; i++) {
        strcpy(krkt,MYDIR);
        if (file[i] == NULL)
            exit(3);
        strcat(krkt,file[i]);
        iterator[i] = strdup(krkt);
        printf("%s\n",iterator[i]);
    }

    printf("\nMaster is starting\n");

    pthread_t tid1[counter1];
    pthread_t tid2[counter1];
    pthread_t tid3[counter1];
    pthread_attr_t attr;

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
    printf("\nslave1 start\n");
    printf("\n~Project Statistics~\n");

    //sleep(2);
    for (i = 0; i < counter1; i++)
        rc = pthread_create(&tid1[i],&attr,project_statistics,(void *) i);

    for (i = 0; i < counter1; i++)
        rc = pthread_join(tid1[i],NULL);
    printf("\nslave1 done\n");

    pid = fork();
    if (pid == 0) {
        printf("\nslave2 start\n");
        printf("\n~Midterm Statistics~\n");

        for (i = 0; i < counter1; i++)
            rc = pthread_create(&tid2[i],&attr,midterm_statistics,(void *) i);

        for (i = 0; i < counter1; i++)
            rc = pthread_join(tid2[i],NULL);

        printf("\nslave2 done\n");
        exit(0);
    }

    pid1 = fork();
    if (pid1 == 0) {
        printf("\nslave3 start\n");
        printf("\n~Final Statistics~\n");

        for (i = 0; i < counter1; i++)
            rc = pthread_create(&tid3[i],&attr,final_statistics,(void *) i);

        for (i = 0; i < counter1; i++)
            rc = pthread_join(tid3[i],NULL);

        printf("\nslave3 done\n");
        exit(0);
    }

    waitpid(pid,NULL,0);
    waitpid(pid1,NULL,0);
    printf("\nMaster is done\n");

    pthread_attr_destroy(&attr);

    return 0;
}
Comments