为什么我在 Kali VM 中不断中止(核心转储)?

why I keep getting Aborted (core dumped) in Kali VM?

我正在做一个项目 C 中的项目,它的重点是创建一个多线程并与它们一起工作...... 问题是该程序在我的 Mac 上运行良好,但是当我尝试处理项目时,Kali VM 或 WSL(Windows 子系统 Linux)。同样的代码给了我以下错误

kali VM 错误

└─$ ./a.out 3 800 200 200 1200                                                                                                                                                                 134 ⨯
malloc(): corrupted top size
zsh: abort      ./a.out 3 800 200 200 1200

WSL上的错误

└─$ ./a.out 2 60 60 20 
malloc(): corrupted top size
Aborted (core dumped)

您可以在此处查看完整代码 in this repo

这是代码的主要文件:

#include "philosophers.h"

int ft_error_put(char *messsage, int ret)
{
    printf("%s\n", messsage);
    return (ret);
}

int ft_parsing(char **av, t_simulation *simulation)
{
    int             num;
    int             i;
    int             j;

    i = 1;
    j = 0;
    while (av[i])
    {
        j = 0;
        num = 0;
        while (av[i][j])
        {
            if (av[i][j] >= '0' && av[i][j] <= '9')
                 num = num * 10 + (av[i][j] - '0');
            else
                return (ft_error_put("Error: Number Only", 1));
            j++;
        }
        if (i == 1)
        {
            simulation->philo_numbers = num;
            simulation->forks = num;
            simulation->threads = (pthread_t *)malloc(sizeof(pthread_t) * num);
        }
        else if (i == 2)
            simulation->time_to_die = num;
        else if (i == 3)
            simulation->time_to_eat = num;
        else if (i == 4)
            simulation->time_to_sleep = num;
        else if (i == 5)
            simulation->eat_counter = num;
        i++;
    }
    if (i == 5)
        simulation->eat_counter = -1;
    return (0);
}

void    ft_for_each_philo(t_simulation *simulation, t_philo *philo, int i)
{
    philo[i].index = i + 1;
    philo[i].left_hand = i;
    philo[i].right_hand = (i + 1) % simulation->philo_numbers;
    philo[i].is_dead = NO;
    if (simulation->eat_counter == -1)
        philo[i].eat_counter = -1;
    else
        philo[i].eat_counter = simulation->eat_counter;
}

t_philo *ft_philo_init(t_simulation *simulation)
{
    t_philo *philo;
    int     i;

    i = -1;
    philo = (t_philo *)malloc(sizeof(t_philo));
    while (++i < simulation->philo_numbers)
        ft_for_each_philo(simulation, philo, i);
    return (philo);
}

void    *ft_routine(void *arg)
{
    t_philo *philo;

    philo = (t_philo *)arg;
    printf("thread number %d has started\n", philo->index);
    sleep(1);
    printf("thread number %d has ended\n", philo->index);
    return (NULL);
}

int main(int ac, char **av)
{
    int             i;
    t_simulation    simulation;
    t_philo         *philo;

    i = 0;
    if (ac == 5 || ac == 6)
    {
        if (ft_parsing(av, &simulation))
            return (1);
        philo = ft_philo_init(&simulation);
        while (i < simulation.philo_numbers)
        {
            simulation.philo_index = i;
            pthread_create(simulation.threads + i, NULL,
                ft_routine, philo + i);
            i++;
        }
        i = 0;
        while (i < simulation.philo_numbers)
        {
            pthread_join(simulation.threads[i], NULL);
            i++;
        }
    }
    return (0);
}

您的程序在 pthread_create 调用时中止。

但是,问题是在 ft_philo_init 之前的 malloc 调用太短了。

您只为 一个 t_philo 结构分配了足够的 space 而不是 philo_numbers

旁注: 不要转换 malloc 的 return 值。参见:Do I cast the result of malloc?

这是更正后的函数:

t_philo *
ft_philo_init(t_simulation *simulation)
{
    t_philo *philo;
    int i;

    i = -1;

// NOTE/BUG: not enough elements allocated
#if 0
    philo = (t_philo *) malloc(sizeof(t_philo));
#else
    philo = malloc(sizeof(*philo) * simulation->philo_numbers);
#endif

    while (++i < simulation->philo_numbers)
        ft_for_each_philo(simulation, philo, i);

    return philo;
}

更新:

thank you it's worked now, but can you explain why it work on macOS but it doesn't in kali? – DarkSide77

嗯,它在 macOS 上“工作”...

当我们对数组进行索引并超出 数组的边界时,它是 UB(“未定义行为”)。 UB 的意思就是:未定义 行为。

参见:

  1. Undefined, unspecified and implementation-defined behavior
  2. Is accessing a global array outside its bound undefined behavior?

任何事情 都可能发生。那是因为philo数组占用了一定的内存。那个分配之后是什么?假设 philo 是 8 个字节 [或元素,如果你愿意——没关系]:

| philo[8]                      | whatever                      |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |

只要我们保持在界限内,一切都很好(例如):

for (i = 0;  i < 8;  ++i)
    philo[i] = 23;

如果我们超越终点,我们有 UB(例如):

for (i = 0;  i < 9;  ++i)
    philo[i] = 23;

这里我们更进一步,修改了 whatever 的第一个单元格。

根据链接器放置的变量,可能有几种行为:

  1. 程序 似乎 到 运行 正常。
  2. whatever 处的一个值已损坏,程序 运行s 但产生了不正确的结果。
  3. whatever 与写保护的页面对齐。该程序将立即出现保护异常。
  4. whatever 处损坏的值没有 即时 效果,但稍后程序会检测到损坏。
  5. 损坏最终会导致段错误,因为指针值已损坏。

在两个系统上,您的程序都在做同样的事情。对于我们从 malloc 获得的区域,whatever 是堆管理器用来跟踪分配的内部 struct。该程序正在破坏它。

macOS 上,堆管理器没有检测到这一点。在 linux(glibc),堆管理器做了更好的交叉检查并检测到损坏。