C文件IO的奇怪行为

时间:2014-11-08 22:27:41

标签: c file-io undefined-behavior

我一直在写一个虚拟机,我注意到发生了一些奇怪的事情,尽管我很久以前写过这个函数。无论如何,我的虚拟机会读取这样的文件:

0002 000A 0001 0004 0000

然而,当我在0000或新行之后有任何空格时......它会崩溃。另一个非常奇怪的事情,让我相信它是文件加载,是当你从文件中删除0000时,空格......它有效吗?!我试过通过GDB运行它,但它确实有效 - 显然这被称为heisenbug或其他东西。我认为这是由于文件的加载方式,您可以在this function here on github中看到,或者只是阅读下面的代码段。

void load_program(vm *self) {
    FILE *file = fopen("testing.ayy", "r");

    if (file != NULL) {
        if (fseek(file, 0, SEEK_END) == 0) {
            long file_size = ftell(file);
            if (file_size == -1) {
                perror("could not read filesize\n");
                exit(1);
            }
            self->source = malloc(sizeof(char) * file_size);

            if (fseek(file, 0, SEEK_SET) != 0) {
                perror("could not reset file index\n");
                exit(1);
            }

            size_t file_length = fread(self->source, sizeof(char), file_size, file);
            if (file_length == 0) {
                perror("given file is empty\n");
                exit(1);
            }
            self->source[file_size] = '\0';
        }
        fclose(file);
    }
    else {
        perror("could not read file: \n");
        exit(1);
    }

    self->source_compact = strdup(self->source);
    self->source_compact = deblank(self->source_compact);

    // here we divide because strlen is in characters,
    // whereas each instruction code should be 4 characters
    // so we're converting char size to num of instructions
    self->instructions_size = strlen(self->source_compact) / INSTRUCTION_LENGTH;

    int i;
    for (i = 0; i < self->instructions_size; i++) {
        char *instr = substring(self->source_compact, i);

        if (strcmp(instr, ERROR_CODE)) { // not equal to NOPE
            if (self->instructions != NULL) {
                self->instructions = add_instructions(self->instructions, strtol(instr, NULL, 16));
            }
            else {
                self->instructions = create_instructions(strtol(instr, NULL, 16));
            }
        }
    }

    self->instructions = reverse(self->instructions);
}

但是我添加了一个GitHub链接,因为我不确定它是否是那个功能;或者如果它是由于整个来源发生的任何事情 - 所以如果任何C大师可以帮助我,那将是辉煌的:)。我确定它位于vm.cvm.h,并且对于可怕的代码感到抱歉;我在学习时从未真正关注过File IO(大错误)。

1 个答案:

答案 0 :(得分:1)

self->source = malloc(sizeof(char) * file_size);
...
self->source[file_size] = '\0';

您需要为终止零分配一个字节。索引source[file_size]实际上是超出分配内存末尾的一个字节。写入该位置可能会破坏malloc()使用的其他变量或内部结构。成功:

self->source = malloc(sizeof(char) * (file_size + 1));

或只是:

self->source = malloc(file_size + 1);

sizeof(char)始终为1,因此它是多余的。

如果您希望在self->source的类型发生变化时保护自己,可以使用:

self->source = malloc ((file_size+1) * sizeof *self->source);

自动分配正确的大小。

在尝试访问内存之前,您还应该检查分配是否成功。