Home > database >  Segmentation fault in a c code, involving multithread
Segmentation fault in a c code, involving multithread

Time:01-22

I have problems with my code. It's a multithreading program that executes the following Linux command "# cat | sort | uniq -c | sort -nr". When I try to run the program in a virtual machine, I get a segmentation error, no core dumped. I have tried everything to fix this, but I still get the error. I see that the problem is in the main function and I don't know what it is. Could be either in pthread_join or maybe could be the max number of threads, declared globally. Can someone help me out? This is my code.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

#define MAX_THREADS 0x40
#define MAX_STRING 124ULL

struct string_count_entry {
    char* string;
    int count;
};

struct string_count {
    int nb_string;
    struct string_count_entry* entries;
};

struct string_count* string_count_init() {

    struct string_count* sc;

    sc = malloc(sizeof(sc));

    sc->entries = NULL;
    sc->nb_string = 0;

    return sc;
}

int addstring(struct string_count* pt, char* s) {
    int i;

    for (i = 0; i < pt->nb_string; i  ) {
        if (strcmp(pt->entries[i].string, s))
            break;
    }

    if (i == pt->nb_string) {
        pt->entries = realloc(pt->entries,
                pt->nb_string   1 * sizeof(pt->entries[0]));
        if (pt->entries == NULL)
            return -1;
        pt->nb_string  ;
        pt->entries[i].string = s;
    }

    pt->entries[i].count  ;
    return 0;
}

static inline int Compare(const void* pt1, const void* pt2) {   
    struct string_count_entry* a = malloc(sizeof(pt2));
    struct string_count_entry* b = malloc(sizeof(pt1));

    if (a->count == b->count) 
        return strcmp(a->string, b->string);
    return a->count - b->count;
}

void string_count_pint(struct string_count* sc) {
    int i;
    
    qsort(sc->entries, sc->nb_string, sizeof(struct string_count), Compare);

    i = 0;
    while (i < sc->nb_string) {
        printf("%d %s\n", sc->entries[i].count, sc->entries[i].string);
        i  ;
    }
}

void string_count_free(void* pt) {
    struct string_count* sc = malloc(sizeof(pt));
    char i;

    for (i = 0; i < sc->nb_string; i  ) {
        free(sc->entries[i].string);
    }
    free(sc->entries);
}

char* readline(void) {
    int i = 0;
    char c;
    char* linebuf = (char*)malloc(MAX_STRING);

    while (read(0, &c, 1) != 0) {
        if (c == '\n') {
            linebuf[i] = '\0';
            return linebuf;
        }
        linebuf[i  ] = c;
    }
    return NULL;
}

void* thread_main(void* arg) {
    struct string_count* sc = malloc(sizeof(arg));
    char* line;

    while ((line == readline()) != '\0') {
        addstring(sc, line);
    }
    return NULL;
}

int main(int argc, char** argv) {
    int nbthreads;
    int i;
    pthread_t threads[MAX_THREADS];
    struct string_count* sc;

    if (argc != 1) {
        fprintf(stderr, "usage: %s <nb threads>\n", argv[0]);
        return EXIT_FAILURE;
    }

    nbthreads = atoi(argv[1]);

    sc = malloc(sizeof(nbthreads));

    for (i = 0; i < nbthreads; i  ) {
        pthread_create(&threads[i], NULL, thread_main, sc);
    }

    do {
        pthread_join(threads[nbthreads--], NULL);
    } while (nbthreads > 0);

    string_count_free(sc);
    string_count_pint(sc);

    return EXIT_SUCCESS;
}

CodePudding user response:

I suspect the bug is in this line: sc = malloc(sizeof(nbthreads));

You probably wanted sc = malloc(sizeof(string_count));

I'm also not sure if struct string_count* sc = malloc(sizeof(arg)); does what you intended in thread_main.

You probably need the sc in main be an array and pass a different item in it to each thread and then aggregate them after the join.

CodePudding user response:

Here are the first few errors I have spotted, in no particular order.

  1. Unprotected modification of data structures from multiple threads. Read something about multithreading. Pay attention to the word "mutex".
  2. pthread_join(threads[nbthreads--], NULL); goes out of bounds.
  3. struct string_count* sc = malloc(sizeof(arg)); makes no sense. sizeof(arg) is the size of a pointer (8 on most PC-like systems). This is not enough to hold one struct string_count.
  4. struct string_count_entry* a = malloc(sizeof(pt2)); apparently has even less sense. You are allocating something in a string comparison function, using a wrong size, then you are using the allocated memory without initializing it, and without even trying to compare the things passed to the function.
  5. while ((line == readline()) != '\0') does not assign anything.
  6. pt->entries = realloc(pt->entries, pt->nb_string 1 * sizeof(pt->entries[0])); is missing a couple of parentheses.
  •  Tags:  
  • Related