gpt4 book ai didi

c - 带有 -O3 标志的段错误

转载 作者:行者123 更新时间:2023-11-30 19:06:55 27 4
gpt4 key购买 nike

编辑:如果我浪费了你们的时间,我真的很抱歉,发布这个问题时我已经没有时间了。这是我已尽力最小化的代码

#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum Error {
ERROR_UNRESOLVED_NAME = 1,
ERROR_CANNOT_OPEN_FILE,
ERROR_NO_ARGV,
ERROR_UNRECOGNIZED_SYMBOL,
ERROR_UNCOMPLETED_SENTENCE,
ERROR_RECURSIVE_SELF
};

struct _Piece;
typedef struct _Piece *(*PieceFunc)(struct _Piece *, void *);
struct _Piece {
PieceFunc function;
void *backpack;
};
typedef struct _Piece Piece;

Piece *piece_create(PieceFunc func, void *pack) {
Piece *piece = malloc(sizeof(Piece));
piece->function = func;
piece->backpack = pack;
return piece;
}

typedef struct _Record {
char *name;
int name_len;
Piece *piece;
struct _Record *previous;
} Record;

Record *record_register(Record *pre, char *name, int name_len, Piece *piece) {
Record *record = malloc(sizeof(Record));
record->name = name;
record->name_len = name_len;
record->piece = piece;
record->previous = pre;
return record;
}

typedef struct {
char *file_name;
char *source;
int length;
int current;
int line;
int column;
} Source;

Source *source_create(char *s, int len, char *file_name) {
Source *source = malloc(sizeof(Source));
source->source = s;
source->file_name = file_name;
source->length = len;
source->current = 0;
source->line = source->column = 1;
return source;
}

Piece *apply(Piece *caller, Piece *callee) {
return caller->function(callee, caller->backpack);
}

// Part 3, internals
Piece *internal_self(Piece *callee, void *backpack) {
if (callee->function == internal_self) {
fprintf(stderr,
"recursive `self` calling between two pieces\n"
"piece 1 backpack: %p\n"
"piece 2: %p backpack: %p",
backpack, callee, callee->backpack);
exit(ERROR_RECURSIVE_SELF);
}
return apply(callee, piece_create(internal_self, backpack));
}

Piece *internal_put(Piece *callee, void *backpack) {
int *p_char = callee->backpack;
putchar(*p_char);
return piece_create(internal_self, NULL);
}

Source *main_create_source(char *file_name) {
FILE *source_file = fopen(file_name, "r");
if (!source_file) {
fprintf(stderr, "cannot open file \"%s\"\n", file_name);
exit(ERROR_CANNOT_OPEN_FILE);
}

char *source = NULL;
int length = 0;
while (true) {
char *line = NULL;
int line_len = 0;
line_len = (int)getline(&line, (size_t *)&line_len, source_file);
if (line_len < 0) {
break;
}
if (source == NULL) {
source = line;
} else {
source = realloc(source, sizeof(char) * (length + line_len + 1));
strcat(source, line);
// free(line);
}
length += line_len;
}
fclose(source_file);
return source_create(source, length, file_name);
}

#define MAIN_REGISTER_INTERNAL(record, name, func) \
record = record_register(record, name, sizeof(name) - 1, \
piece_create(func, NULL)); \
printf("%p %p\n", record, record->previous);

int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "please specify source file by command line argument\n");
exit(ERROR_NO_ARGV);
}

Record *r = NULL;
MAIN_REGISTER_INTERNAL(r, "put", internal_put);
printf("main %p\n", r);

Source *s = main_create_source(argv[1]);

printf("main %p\n", r);
}

起初,程序因段错误而崩溃,我找到了错误访问代码行,该代码行已在本代码演示中删除。我发现原来的错误是那个变量 rmain在对 main_create_source 进行不相关的调用后会出现意外的变化,演示如下(将此代码文件另存为 foo.c )

$ cc -O0 -g foo.c        
$ ./a.out futaba_test.ftb
0x7fc0024025b0 0x0
main 0x7fc0024025b0
main 0x7fc0024025b0
$ cc -O3 -g foo.c
$ ./a.out futaba_test.ftb
0x7fe861c025b0 0x0
main 0x7fe861c025b0
main 0x7fe800000000

更改优化级别时,行为会发生变化。与EOF无关因为我已经删除了它,并且在我看来strcat的内存目的地够丰富。感谢您的帮助。

顺便说一句,如果有任何要求,请指出此片段的用途。这是我正在研究的一种最小语言的解释器。它能够评估当时的小源代码片段,这是我第一次尝试使用 -O3 构建它。 。如果不进行任何关卡优化,该错误就会消失。

<小时/>

(以下为原帖,可忽略。)

我有这个code file 。当使用 cc -O0 futaba.c 编译时,并使用 ./a.out futaba_test.ftb 运行它,结果将是

0x7fba60c025b0 0x0
0x7fba60c025e0 0x7fba60c025b0
0x7fba60c02610 0x7fba60c025e0
0x7fba60c02640 0x7fba60c02610
0x7fba60c02670 0x7fba60c02640
0x7fba60c026b0 0x7fba60c02670
0x7fba60c026d0 0x7fba60c026b0
0x7fba60c02700 0x7fba60c026d0
0x7fba60c02730 0x7fba60c02700
main 0x7fba60c02730
main 0x7fba60c02730
A%

(Zsh 添加后缀 % )一切顺利。但是当用 -O3 编译时而不是-O0 ,结果将是

0x7f8f274025b0 0x0
0x7f8f274025e0 0x7f8f274025b0
0x7f8f27402610 0x7f8f274025e0
0x7f8f27402640 0x7f8f27402610
0x7f8f27402670 0x7f8f27402640
0x7f8f274026b0 0x7f8f27402670
0x7f8f274026d0 0x7f8f274026b0
0x7f8f27402700 0x7f8f274026d0
0x7f8f27402730 0x7f8f27402700
main 0x7f8f27402730
main 0x7f8f00000000
[1] 27811 segmentation fault ./a.out futaba_test.ftb

最后两个main行打印不同的地址,第二个无效,这导致了后面record_resolve中的堆栈溢出错误功能。

问题是什么?

最佳答案

代码很多,但这里至少有一个标志:

char source_fetch(Source *s) {
return s->current == s->length ? EOF : s->source[s->current];
}

这会强制将 EOF 转换为 char,这是一个非常糟糕的主意。这就是为什么所有可以返回 EOF 的标准 C 函数(例如 getchar())都返回 int

不知道优化编译器可以从中得到什么,但是一旦你考虑使用它等待 EOF 的代码......它很臭。

注意:这可能是不好的答案;但它指出了代码的一个具体问题。

此外,所有堆分配似乎都没有返回寻找 NULL 的代码;这也有点可怕。

关于c - 带有 -O3 标志的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47411245/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com