3

我遇到了一个我无法弄清楚的分段错误。导致分段错误的函数如下所示:

Expression *IntegerLiteral_init(int intgr) {
    Expression *the_exp = safe_alloc(sizeof(Expression));
    the_exp->type = expr_IntegerLiteral;
    the_exp->expr->intgr = intgr;
    the_exp->exec_count = 0;
    return the_exp;
}

定义了一个表达式:

typedef struct {
    expr_type type;
    u_expr *expr;
    int exec_count;
} Expression;

u_expr 和 expr_type 被定义:

typedef union {
    char *ident;
    int intgr;
} u_expr;

typedef enum {
    expr_Identifier,
    expr_IntegerLiteral
} expr_type;

expr_typeexpr_IntegerLiteral和的枚举expr_Identifier

根据GDB,段错误是由在线引起的:the_exp->expr->intgr = intgr;. 奇怪的是,它并不总是导致段错误 - 如果我以这种方式调用函数,则会发生段错误:

Expression *e = IntegerLiteral_init(0);

但在我程序的另一部分,我使用以下方法调用它:

Expression *e;

...

e = IntegerLiteral_init(
    (int)strtol(num_str, (char **)NULL, 10));

没有任何问题。num_str已从某些输入中解析并具有值"0".

如果给定的参数相同,我不明白为什么我调用的上下文IntegerLiteral_init()会影响是否发生此段错误。intgr如果有人能对此有所了解,我将不胜感激。

4

2 回答 2

8

线

the_exp->expr->intgr = intgr;

正在写入未初始化的指针。您已为the_exp但未分配内存the_exp->expr。最简单的解决方法可能是更改Expressionu_expr按值而不是指针

typedef struct {
    expr_type type;
    u_expr expr;
    int exec_count;
} Expression;

如果你不能这样做,IntegerLiteral_init可以更改为分配内存the_exp->expr

Expression *IntegerLiteral_init(int intgr) {
    Expression *the_exp = safe_alloc(sizeof(Expression));
    the_exp->type = expr_IntegerLiteral;
    the_exp->expr = safe_alloc(sizeof(*the_exp->expr));
    the_exp->expr->intgr = intgr;
    the_exp->exec_count = 0;
    return the_exp;
}

如果您尝试后一种方法,请确保在 freethe_exp->expr时也 free the_exp

关于为什么IntegerLiteral_init()有时似乎有效,访问未分配的内存会导致未定义的行为。有时你很幸运,这会立即崩溃,让你可以使用调试器准确查看问题出在哪里。其他时候你不太幸运并且你的程序继续执行,只是当其他一些代码试图访问损坏的内存时很久之后才会崩溃IntegerLiteral_init()

于 2013-07-24T12:54:23.967 回答
2

It looks like you do not initialize u_expr *expr, it probably points to memory that will give you segmentation fault if you access it.

于 2013-07-24T12:54:56.213 回答