Why I'm getting stack smashing?

57 Views Asked by At

I'm trying to solve the Dinning Philosophers using C, and not only my threads do not stop when I philosopher die, but I'm also getting stack smashing, here is my code:

//main.js
static void create_threads(
    pthread_t *threads, pthread_t *death_threads,
    t_philo *philos, int n)
{
    int i;

    i = 0;
    while (i < n)
    {
        pthread_create(&threads[i], NULL, dinning_handler, &philos[i]);
        pthread_create(&death_threads[i], NULL, death_monitor, &philos[i]);
        i++;
    }
    return ;
}

static void join_threads(pthread_t *threads, pthread_t *death_threads, int n)
{
    int i;

    i = 0;
    while (i < n)
    {
        pthread_join(threads[i], NULL);
        pthread_join(death_threads[i], NULL);
        i++;
    }
    return ;
}

static void destroy_mutexes(pthread_mutex_t *forks, t_philo *philos, int n)
{
    int i;

    i = 0;
    while (i < n)
    {
        pthread_mutex_destroy(&forks[i]);
        pthread_mutex_destroy(&philos[i].last_meal_mutex);
        pthread_mutex_destroy(&philos[i].eating_mutex);
        i++;
    }
    return ;
}

static void free_resources(
    pthread_t *threads, pthread_t *death_threads,
    pthread_mutex_t *forks, t_philo *philos)
{
    free(philos);
    free(forks);
    free(threads);
    free(death_threads);
}

int main(int argc, char **argv)
{
    pthread_mutex_t *forks;
    pthread_t       *threads;
    pthread_t       *death_threads;
    t_philo         *philos;
    int             max_eats;
    pthread_mutex_t alive_mutex;

    validate_args(argc, argv);
    max_eats = -1;
    if (argc > 5)
        max_eats = ft_atoi(argv[5]);
    forks = NULL;
    threads = NULL;
    death_threads = NULL;
    philos = NULL;
    pthread_mutex_init(&alive_mutex, NULL);
    if (!init_philos(&philos, &forks, argv, max_eats, &alive_mutex))
        exit(EXIT_FAILURE);
    if (!init_threads(&threads, &death_threads, ft_atoi(argv[1])))
        exit_gracefully(philos, forks);
    create_threads(threads, death_threads, philos, ft_atoi(argv[1]));
    join_threads(threads, death_threads, ft_atoi(argv[1]));
    pthread_mutex_destroy(&alive_mutex);
    destroy_mutexes(forks, philos, ft_atoi(argv[1]));
    free_resources(threads, death_threads, forks, philos);
    return (0);
}

Maybe the problem is here, in the fact that I have one monitor per philosopher

//initialize.c
#include "philo.h"

static void fill_philos(
    char **argv, pthread_mutex_t **forks, \
    t_philo **philos, int max_eats, pthread_mutex_t *alive_mutex
)
{
    int i;
    int n_philosophers;
    int someone_die;

    n_philosophers = ft_atoi(argv[1]);
    i = 0;
    someone_die = 0;
    while (i < n_philosophers)
    {
        pthread_mutex_init(&(*forks)[i], NULL);
        pthread_mutex_init(&(*philos)[i].last_meal_mutex, NULL);
        pthread_mutex_init(&(*philos)[i].eating_mutex, NULL);
        (*philos)[i].id = i + 1;
        (*philos)[i].eats = 0;
        (*philos)[i].eating = 0;
        (*philos)[i].someone_die = &someone_die;
        (*philos)[i].time_to_eat = ft_atoi(argv[3]);
        (*philos)[i].time_to_sleep = ft_atoi(argv[4]);
        (*philos)[i].time_to_die = ft_atoi(argv[2]);
        (*philos)[i].max_eats = max_eats;
        (*philos)[i].left_fork = &(*forks)[i];
        (*philos)[i].right_fork = &(*forks)[(i + 1) % n_philosophers];
        (*philos)[i].alive_mutex = alive_mutex;
        i++;
    }
}

int init_philos(
    t_philo **philos, pthread_mutex_t **forks, \
    char **argv, int max_eats, pthread_mutex_t *alive_mutex
)
{
    int n_philosophers;

    n_philosophers = ft_atoi(argv[1]);
    (*philos) = malloc(sizeof(t_philo) * n_philosophers);
    if (!(*philos))
    {
        printf("\033[0;31mError trying to create philosophers\033[0m");
        return (0);
    }
    (*forks) = malloc(sizeof(pthread_mutex_t) * n_philosophers);
    if (!(*forks))
    {
        printf("\033[0;31mError trying to create forks\033[0m");
        return (0);
    }
    fill_philos(argv, forks, philos, max_eats, alive_mutex);
    return (1);
}

int init_threads(
    pthread_t **threads, pthread_t **death_threads,
    int n_philosophers
)
{
    (*threads) = malloc(sizeof(pthread_t) * n_philosophers);
    if (!(*threads))
    {
        printf("\033[0;31mError trying to create threads\033[0m");
        return (0);
    }
    (*death_threads) = malloc(sizeof(pthread_t) * n_philosophers);
    if (!(*death_threads))
    {
        printf("\033[0;31mError trying to create death threads\033[0m");
        return (0);
    }
    return (1);
}
//thread_handler.c

#include "philo.h"

static void eat(t_philo *philo)
{
    pthread_mutex_lock(&philo->eating_mutex);
    philo->eating = 1;
    pthread_mutex_unlock(&philo->eating_mutex);
    print_green("is eating", philo->id, get_ts_in_ms());
    pthread_mutex_lock(&philo->last_meal_mutex);
    gettimeofday(&philo->last_meal_time, NULL);
    pthread_mutex_unlock(&philo->last_meal_mutex);
    ft_usleep(philo->time_to_eat);
    philo->eats++;
    pthread_mutex_lock(&philo->eating_mutex);
    philo->eating = 0;
    pthread_mutex_unlock(&philo->eating_mutex);
}

static void p_sleep(t_philo *philo)
{
    print_blue("is sleeping", philo->id, get_ts_in_ms());
    ft_usleep(philo->time_to_sleep);
}

static void assign_fork(t_philo *philo, \
pthread_mutex_t **first, pthread_mutex_t **second)
{
    if (philo->id % 2 == 0)
    {
        (*first) = philo->left_fork;
        (*second) = philo->right_fork;
    }
    else
    {
        (*first) = philo->right_fork;
        (*second) = philo->left_fork;
    }
}

int dead_loop(t_philo *philo)
{
    pthread_mutex_lock(philo->alive_mutex);
    if (*philo->someone_die == 1)
        return (pthread_mutex_unlock(philo->alive_mutex), 1);
    pthread_mutex_unlock(philo->alive_mutex);
    return (0);
}

void    *dinning_handler(void *arg)
{
    pthread_mutex_t *first_fork;
    pthread_mutex_t *second_fork;
    t_philo         *philo;

    philo = (t_philo *)arg;

    pthread_mutex_lock(&philo->last_meal_mutex);
    gettimeofday(&philo->last_meal_time, NULL);
    pthread_mutex_unlock(&philo->last_meal_mutex);

    first_fork = NULL;
    second_fork = NULL;
    while (!dead_loop(philo) && (philo->max_eats == -1 || philo->eats < philo->max_eats))
    {
        assign_fork(philo, &first_fork, &second_fork);
        pthread_mutex_lock(first_fork);
        print_blue("has taken a fork", philo->id, get_ts_in_ms());
        pthread_mutex_lock(second_fork);
        print_blue("has taken a fork", philo->id, get_ts_in_ms());
        eat(philo);
        pthread_mutex_unlock(second_fork);
        pthread_mutex_unlock(first_fork);
        p_sleep(philo);
        print_blue("is thinking", philo->id, get_ts_in_ms());
    }
    return (NULL);
}

void    *death_monitor(void *arg)
{
    t_philo *philo;
    long    elapsed_time;
    int     is_eating;

    philo = (t_philo *)arg;
    while (!dead_loop(philo))
    {
        usleep(10000);
        pthread_mutex_lock(&philo->eating_mutex);
        is_eating = philo->eating;
        pthread_mutex_unlock(&philo->eating_mutex);
        if (is_eating)
            continue ;
        pthread_mutex_lock(&philo->last_meal_mutex);
        elapsed_time = get_elapsed_time(&philo->last_meal_time);
        pthread_mutex_unlock(&philo->last_meal_mutex);
        if (elapsed_time > philo->time_to_die)
        {
            print_red("died", philo->id, get_ts_in_ms());
            pthread_mutex_lock(philo->alive_mutex);
            *philo->someone_die = 1;
            pthread_mutex_unlock(philo->alive_mutex);
            break ;
        }
    }
    return (NULL);
}
//time_handler.c
#include "philo.h"

long    get_elapsed_time(struct timeval *start)
{
    struct timeval  now;
    long            elapsed_time;

    gettimeofday(&now, NULL);
    elapsed_time = (now.tv_sec - start->tv_sec) * 1000 + \
    (now.tv_usec - start->tv_usec) / 1000;
    return (elapsed_time);
}

long    get_ts_in_ms(void)
{
    struct timeval  time;

    gettimeofday(&time, NULL);
    return ((time.tv_sec * 1000) + (time.tv_usec / 1000));
}
//utils.c
void    exit_gracefully(t_philo *philos, pthread_mutex_t *forks)
{
    free(philos);
    free(forks);
    exit(EXIT_FAILURE);
}

void    ft_usleep(int ms)
{
    long int    time;

    time = get_ts_in_ms();
    while (get_ts_in_ms() - time < ms)
        usleep(ms / 10);
}

I know that the code has memory leaks, but I'm aiming to solve after I solve this stack smash problem.

EDIT: Here are some logs that i get using lldb and the thread sanitizer flag:

* thread #2, stop reason = EXC_BAD_ACCESS (code=2, address=0x100000000)
  * frame #0: 0x00000001833b5a90 libsystem_pthread.dylib`_pthread_joiner_prepost_wake + 84
    frame #1: 0x00000001833b3bc4 libsystem_pthread.dylib`_pthread_terminate + 300
    frame #2: 0x00000001833b3a98 libsystem_pthread.dylib`_pthread_terminate_invoke + 92
    frame #3: 0x00000001833b6740 libsystem_pthread.dylib`_pthread_exit + 112
    frame #4: 0x00000001833b6040 libsystem_pthread.dylib`_pthread_start + 148
ThreadSanitizer:DEADLYSIGNAL
==49995==ERROR: ThreadSanitizer: SEGV on unknown address 0x000100000000 (pc 0x0001833b5a90 bp 0x00016b623f60 sp 0x00016b623f10 T300488)
==49995==The signal is caused by a WRITE memory access.
ThreadSanitizer:DEADLYSIGNAL
ThreadSanitizer: nested bug in the same thread, aborting.
1

There are 1 best solutions below

1
user23612113 On

Well that really unreadable.

I look your code and i didn't find the error, and that not surprising.

At some point project become so big, it's really hard to find a bug, even more if you not in the project.

That also why pp ask for a minimal example.

I think, is time for you to take a good look at tool like valgrind, fsanitize, gdb, ext.

And why create 2 thread/philo, and not you not using your main to check death? What you gonna do in your main anyway?

Welcome in the 42 family.