为什么当我关闭时内存大小被覆盖

why is memory size being overwritten when I fclose

提问人:berry acer 提问时间:8/12/2023 最后编辑:berry acer 更新时间:8/12/2023 访问量:78

问:

警告,对不起,这是我的第一篇文章,所以我不知道该怎么做。 只是要尽力详细说明我发现的问题

所以最近我正在研究PNG解码器,但我偶然发现了一个奇怪的“功能”?的文件读取。 我一直收到 malloc 错误,例如 “malloc.c:2617: sysmalloc: 断言 '(old_top == initial_top (av) && old_size == 0) ||((无符号长) (old_size) >= MINSIZE && prev_inuse (old_top) && ((无符号长) old_end & (pagesize - 1)) == 0)' 失败。 和 “[IHDR] 数据:RGBA malloc():下一个大小无效(未排序)”

因此,我决定凭直觉检查分配的内存长度,因为我知道我没有双重释放我的数据,并且我仔细检查了每个指针调用是否有越界的东西。 好吧,在调用 fclose() 时,我的 char* 的大小总是会减少 1。 有谁知道为什么会这样?

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

void checkFP(FILE* fp) {
        if(!fp) {
                printf("couldn't open file\n");
                switch(errno) {
                        case 2:
                                printf("File not found\n");
                                break;
                        case 13:
                                printf("No perms to open file\n");
                                break;
                }
                exit(1);
        }
}

unsigned getAllocLen(char * p) {
        return *(unsigned*)(p-8);
}

int main() {
        unsigned len = 0,
                 orig = 0,
                 l = 0;
        char *buffer,
             *head;

        FILE *fp = fopen("test_1.c", "r");
        checkFP(fp);    

        fseek(fp, 0, SEEK_END);
        len = ftell(fp);
        l = len;
        buffer = malloc(len);
        head = buffer;
        orig = getAllocLen(buffer);
        fseek(fp, 0, SEEK_SET);
        
        while(l) {
                size_t read_bytes = fread(head, 1, l, fp);
                head += read_bytes;
                l -= read_bytes;
        }
        if( fclose(fp) ) {
                printf("Error when closing File\n");
                exit(2);
        }
        if(orig != getAllocLen(buffer)) {
                printf("Uh Ohh Memory corrupted(%p, original len = %u,current len = %u)\n",buffer, orig, getAllocLen(buffer));
                free(buffer);
                exit(3);        
        }

        printf("%s\n",buffer);
        free(buffer);
        return 0;
}

这是我可以得到的显示错误的代码的最小部分

我注意到它仅在我使用 fseek(fp, 0, SEEK_SET) 或 rewind(fp) 重置 fp 时才会发生 因此,当我尝试在分配内存之前先关闭文件,然后再次打开它进行读取时,它并没有损坏大小。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

void checkFP(FILE* fp) {
        if(!fp) {
                printf("couldn't open file\n");
                switch(errno) {
                        case 2:
                                printf("File not found\n");
                                break;
                        case 13:
                                printf("No perms to open file\n");
                                break;
                }
                exit(1);
        }
}

unsigned getAllocLen(char * p) {
        return *(unsigned*)(p-8);
}

int main() {
        unsigned len = 0,
                 orig = 0,
                 l = 0;
        char *buffer,
             *head;
        FILE *fp = fopen("test_1.c", "r");
        checkFP(fp);    

        fseek(fp, 0, SEEK_END);
        len = ftell(fp), l = len;
        if( fclose(fp) ) {
                printf("Error when closing file\n");
                exit(2);
        }

        buffer = malloc(len);
        head = buffer;
        orig = getAllocLen(buffer);
        
        fp = fopen("test_1.c", "r");
        checkFP(fp);
        while(l) {
                size_t read_bytes = fread(head, 1, l, fp);
                head += read_bytes;
                l -= read_bytes;
        }
        if( fclose(fp) ) {
                printf("Error when closing File\n");
                exit(2);
        }
        if(orig != getAllocLen(buffer)) {
                printf("Uh Ohh Memory corrupted(%p, original len = %u,current len = %u)\n",buffer, orig, getAllocLen(buffer));
                free(buffer);
                exit(3);        
        }

        printf("%s\n",buffer);
        free(buffer);
        return 0;
}

如果有人知道,我只是想知道为什么会发生这种情况,从现在开始,我可能会在这里使用此代码,因为它有效。

我还注意到一些有趣的事情,当大小发生变化并且我尝试释放数据时,它没有抛出错误,这是为什么?

C 文件 malloc

评论

2赞 Ted Lyngmo 8/12/2023
这两个代码段都缺少 。不过,从您的缩进位置看不出您想把它放在哪里。}main
2赞 Some programmer dude 8/12/2023
所以你试图绕过或使用(滥用?)一些可能是错误的实现细节?谁告诉你的?你认为你为什么需要它?超出分配的内存范围会导致未定义的行为。只是不要这样做!
3赞 Fe2O3 8/12/2023
您是否考虑过检查返回值?即。不要简单地假设系统调用有效......malloc()
2赞 Weather Vane 8/12/2023
如果要打开PNG文件,则应以二进制模式打开它。但该示例以文本模式打开一个文本文件。文件的大小不一定是要读取的字节数。
2赞 Eric Postpischil 8/12/2023
1067 和 1066 之间的差异可能是内存管理软件用来指示自身某些内容的位,例如“指针链的末端”。返回的分配地址前面的字节包含大小的概念是用于教授入门课程的简单假设。C标准不要求。它可以在某些 C 库实现中使用,但可以修改后使用(或根本不使用)。如果没有库的内部文档,你就不能依赖它,也不能将 1067 ➝ 1066 解释为有意义的更改。

答: 暂无答案