You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Monty解释器pop opcode实现BUG求助:存在double free错误

Monty解释器pop opcode调试问题

我已调试超过24小时,仍无法修复Monty解释器中pop opcode的BUG,以下是相关信息:

测试用例(test.m)

push 1
push 2
push 3
pall
pop
pall
pop
pall
pop
pall

实际输出

3
2
1
0
1
free(): double free detected in tcache 2
Aborted (core dumped)

预期输出

3
2
1
2
1
1

当前pop opcode实现代码

#include "monty.h"

/**
 * pop - removes the top element of the stack
 * @stack: the stack
 * @line_number: current line number of the bytecode file
 *
 * Return: Nothing
 */

void pop(stack_t **stack, unsigned int line_number)
{
    stack_t *temp = NULL;

    if (*stack == NULL)
    {
        dprintf(2, "L%d: can't pop an empty stack\n", line_number);
        exit(EXIT_FAILURE);
    }

    temp = *stack;
    *stack = (*stack)->prev;

    temp->prev = NULL;
    free(temp);

    if (*stack)
        (*stack)->next = NULL;
}

问题分析与修复

核心错误

当前pop代码混淆了双向链表的prev和next指针方向:

  • 标准Monty栈的实现中,新元素通过push添加到链表头部作为栈顶,栈顶节点的next指向旧栈顶,prev为NULL。
  • 你的代码错误地用(*stack)->prev更新栈顶指针,导致栈顶被设置为NULL(栈顶节点的prev原本就是NULL),后续pall访问空指针触发未定义行为(输出0),最终引发重复释放错误。

修复后的pop代码

#include "monty.h"

/**
 * pop - removes the top element of the stack
 * @stack: the stack
 * @line_number: current line number of the bytecode file
 *
 * Return: Nothing
 */

void pop(stack_t **stack, unsigned int line_number)
{
    stack_t *temp = NULL;

    if (*stack == NULL)
    {
        dprintf(2, "L%d: can't pop an empty stack\n", line_number);
        exit(EXIT_FAILURE);
    }

    temp = *stack;
    // 用next指针获取下一个栈顶元素(旧栈顶)
    *stack = (*stack)->next;
    free(temp);

    // 若栈不为空,将新栈顶的prev置为NULL(断开与已释放节点的关联)
    if (*stack)
        (*stack)->prev = NULL;
}

验证说明

修复后:

  1. 第一次pop移除栈顶3,栈顶变为2,pall输出2、1;
  2. 第二次pop移除2,栈顶变为1,pall输出1;
  3. 第三次pop移除1,栈为空,无额外输出;
    完全匹配预期结果,且不会出现重复释放错误。

内容的提问来源于stack exchange,提问作者scisamir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 18:48:09