c - C 文件 IO 的奇怪行为

标签 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 中,对于糟糕的代码深表歉意;我在学习时从未真正深入研究过文件 IO(这是一个大错误)。

最佳答案

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);

它会自动分配正确的大小。

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

关于c - C 文件 IO 的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26822799/

相关文章:

c - 带有指向数组指针的 printf scanf

C - 将一个字节的三位与一个字节组合

C:文件 I/O 循环遍历包含一组数字的文件以找到它们的平方、立方和平方根

Python,按特定顺序运行命令

c - 以不确定的顺序使用具有副作用的函数是否存在不确定的行为?

c - 为什么在 C 中返回给定错误的语句?

c - 从函数返回整数数组

.net - 如何提高进程的 I/O 优先级?

c - 使用带字符串的长度子说明符的 printf 行为

c++ - 基于通用 char[] 的存储并避免与严格别名相关的 UB