C语言 如何从结构体中获得正确的输出?从二进制文件加载信息后

nvbavucw  于 2023-03-28  发布在  其他
关注(0)|答案(1)|浏览(124)

我试图从一个二进制文件中读取数据到一个inode结构中。为了表示一个文件系统。但是我得到了一个分段错误,并且不知道如何修复它。我已经在load_inodes函数和debug_fs函数中打印了地址。我的问题是,如何更改load_inodes,以使其余代码正常工作?我猜我必须使用malloc将数据添加到堆中以使其正确。或者可能条目有问题,因此子输出的地址为0x1
二进制文件如下所示:

00000000: 0000 0000 0200 0000 2f00 0100 0000 0000  ......../.......
00000010: 0200 0000 0100 0000 0000 0000 0200 0000  ................
00000020: 0000 0000 0100 0000 0700 0000 6b65 726e  ............kern
00000030: 656c 0000 0120 4e00 0005 0000 0000 0000  el... N.........
00000040: 0000 0000 0001 0000 0000 0000 0002 0000  ................
00000050: 0000 0000 0003 0000 0000 0000 0004 0000  ................
00000060: 0000 0000 0002 0000 0004 0000 0065 7463  .............etc
00000070: 0001 0000 0000 0001 0000 0003 0000 0000  ................
00000080: 0000 0003 0000 0006 0000 0068 6f73 7473  ...........hosts
00000090: 0000 01c8 0000 0001 0000 0005 0000 0000  ................
000000a0: 0000 00

前四个字节是它的id。接下来的四个是名称的长度。接下来的字节是名称。接下来的两个字节是is_directory和is_readonly。接下来的四个是filesize。接下来的四个是entries。
inode.c的相关部分如下所示:

struct inode* load_inodes()  /* this one works on the first inode loadexample1 */
{
    printf("Start of load_inodes()");
    
    FILE* f = fopen("master_file_table", "rb");
    if (f == NULL) {
        fprintf(stderr, "Failed to open master_file_table for reading\n");
        perror("reason:");
        return NULL;
    }

    printf("NUM_INODES * sizeof: %ld\n\n", NUM_INODES * sizeof(struct inode));
    // Allocate memory for inodes array
    struct inode* inodes = (struct inode*) malloc(NUM_INODES * sizeof(struct inode)+100000);
    printf("ja\n");
    if (inodes == NULL) {
        fprintf(stderr, "Failed to allocate memory for inodes\n");
        fclose(f);
        return NULL;
    }

    printf("Before mainloop\n");

    // Read each inode from the file and store it in the inodes array
    for (int i = 0; i < NUM_INODES; i++) {
        uint32_t id;
        fread(&id, sizeof(uint32_t), 1, f);
        inodes[i].id = id;

        printf("ID: %d\n", id);

        uint32_t name_len;
        fread(&name_len, sizeof(uint32_t), 1, f);
        printf("Namelength: %d\n", name_len);

        char* name = (char*) malloc(name_len + 1);
        if (name == NULL) {
            fprintf(stderr, "Failed to allocate memory for inode name\n");
            fclose(f);
            free(inodes);
            return NULL;
        }
        fread(name, sizeof(char), name_len, f);
        name[name_len] = '\0';
        inodes[i].name = name;
        printf("Name: %s\n", name);

        char is_directory;
        fread(&is_directory, sizeof(char), 1, f);
        inodes[i].is_directory = is_directory;
        printf("Is_directory: %d\n", is_directory);

        char is_readonly;
        fread(&is_readonly, sizeof(char), 1, f);
        inodes[i].is_readonly = is_readonly;
        printf("Is_readonly: %d\n", is_readonly);
        
        
        uint32_t filesize;
        fread(&filesize, sizeof(uint32_t), 1, f);
        inodes[i].filesize = filesize;
        printf("Filesize: %d\n", filesize);

        uint32_t num_entries;
        fread(&num_entries, sizeof(uint32_t), 1, f);
        inodes[i].num_entries = num_entries;
        printf("Num_entries: %d\n", num_entries);

        if (num_entries > 0) {
            uintptr_t* entries = (uintptr_t*) malloc(num_entries * sizeof(uintptr_t));
            if (entries == NULL) {
                fprintf(stderr, "Failed to allocate memory for inode entries\n");
                fclose(f);
                free(inodes);
                return NULL;
            }
            fread(entries, sizeof(uintptr_t), num_entries, f);
            inodes[i].entries = entries;
            printf("Entries: %d\n\n", *entries);
        } else {
            inodes[i].entries = NULL;
        }
    }
    printf("Address: %p  Name: %s\n", inodes[0], inodes[0].name);
    printf("Address: %p  Name: %s\n", inodes[1], inodes[1].name);
    printf("Address: %p  Name: %s\n", inodes[2], inodes[2].name);
    printf("Address: %p  Name: %s\n", inodes[3], inodes[3].name);
    // printf("%d\n", inodes[0].is_directory);
    fclose(f);
    // inode_ptr = malloc(10000)
    return inodes;
}



void fs_shutdown( struct inode* inode )
{
}

/* This static variable is used to change the indentation while debug_fs
 * is walking through the tree of inodes and prints information.
 */
static int indent = 0;

void debug_fs( struct inode* node )
{
    printf("Name: %s Address: %p\n", node->name, &node);
    if( node == NULL ) return;
    for( int i=0; i<indent; i++ )
        printf("  ");
    if( node->is_directory )
    {
        printf("%s (id %d) (address: %p\n", node->name, node->id, node);
        indent++;

        for( int i=0; i<node->num_entries; i++ )
        {
            struct inode* child = (struct inode*)node->entries[i];
            printf("Child: %p\n", child);
            debug_fs( child );
        }
        indent--;
    }
    else
    {
        printf("%s (id %d size %db blocks ", node->name, node->id, node->filesize );
        for( int i=0; i<node->num_entries; i++ )
        {
            printf("%d ", (int)node->entries[i]);
        }
        printf(")\n");
    }
}

load_fs. c的相关部分如下所示:

int main()
{
    printf("===================================\n");
    printf("= Load all inodes from the file   =\n");
    printf("= master_file_table               =\n");
    printf("===================================\n");
    struct inode* root = load_inodes();
    debug_fs( root );
    debug_disk();

使用valgrind运行load_fs后的输出:

===================================
= Load all inodes from the file   =
= master_file_table               =
===================================
Start of load_inodes()NUM_INODES * sizeof: 160

ja
Before mainloop
ID: 0
Namelength: 2
Name: /
Is_directory: 1
Is_readonly: 0
Filesize: 0
Num_entries: 2
Entries: 1

ID: 1
Namelength: 7
Name: kernel
Is_directory: 0
Is_readonly: 1
Filesize: 20000
Num_entries: 5
Entries: 0

ID: 2
Namelength: 4
Name: etc
Is_directory: 1
Is_readonly: 0
Filesize: 0
Num_entries: 1
Entries: 3

ID: 3
Namelength: 6
Name: hosts
Is_directory: 0
Is_readonly: 1
Filesize: 200
Num_entries: 1
Entries: 5

Address: 0x55a9e70  Name: /
Address: 0x55a9f10  Name: kernel
Address: 0x55a9fd0  Name: etc
Address: 0x55aa070  Name: hosts
Name: / Address: 0x1ffefff5c8
/ (id 0) (address: 0x558f6b0
Child: 0x1
==3689174== Invalid read of size 8
==3689174==    at 0x4017E3: debug_fs (inode.c:298)
==3689174==    by 0x4018BA: debug_fs (inode.c:311)
==3689174==    by 0x40199D: main (load_fs.c:13)
==3689174==  Address 0x9 is not stack'd, malloc'd or (recently) free'd
==3689174==
==3689174==
==3689174== Process terminating with default action of signal 11 (SIGSEGV)
==3689174==  Access not within mapped region at address 0x9
==3689174==    at 0x4017E3: debug_fs (inode.c:298)
==3689174==    by 0x4018BA: debug_fs (inode.c:311)
==3689174==    by 0x40199D: main (load_fs.c:13)
==3689174==  If you believe this happened as a result of a stack
==3689174==  overflow in your program's main thread (unlikely but
==3689174==  possible), you can try to increase the size of the
==3689174==  main thread stack using the --main-stacksize= flag.
==3689174==  The main thread stack size used in this run was 8388608.
==3689174==
==3689174== HEAP SUMMARY:
==3689174==     in use at exit: 101,279 bytes in 10 blocks
==3689174==   total heap usage: 12 allocs, 2 frees, 109,959 bytes allocated
==3689174==
==3689174== 23 bytes in 4 blocks are still reachable in loss record 1 of 4
==3689174==    at 0x4C37135: malloc (vg_replace_malloc.c:381)
==3689174==    by 0x4013B9: load_inodes (inode.c:163)
==3689174==    by 0x40198D: main (load_fs.c:12)
==3689174==
==3689174== 72 bytes in 4 blocks are still reachable in loss record 2 of 4
==3689174==    at 0x4C37135: malloc (vg_replace_malloc.c:381)
==3689174==    by 0x4015ED: load_inodes (inode.c:197)
==3689174==    by 0x40198D: main (load_fs.c:12)
==3689174==
==3689174== 1,024 bytes in 1 blocks are still reachable in loss record 3 of 4
==3689174==    at 0x4C37135: malloc (vg_replace_malloc.c:381)
==3689174==    by 0x52500FF: _IO_file_doallocate (in /usr/lib64/libc-2.28.so)
==3689174==    by 0x525E06F: _IO_doallocbuf (in /usr/lib64/libc-2.28.so)
==3689174==    by 0x525D2D7: _IO_file_overflow@@GLIBC_2.2.5 (in /usr/lib64/libc-2.28.so)
==3689174==    by 0x525C47E: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib64/libc-2.28.so)
==3689174==    by 0x5252542: puts (in /usr/lib64/libc-2.28.so)
==3689174==    by 0x401965: main (load_fs.c:8)
==3689174==
==3689174== 100,160 bytes in 1 blocks are still reachable in loss record 4 of 4
==3689174==    at 0x4C37135: malloc (vg_replace_malloc.c:381)
==3689174==    by 0x4012C3: load_inodes (inode.c:141)
==3689174==    by 0x40198D: main (load_fs.c:12)
==3689174==
==3689174== LEAK SUMMARY:
==3689174==    definitely lost: 0 bytes in 0 blocks
==3689174==    indirectly lost: 0 bytes in 0 blocks
==3689174==      possibly lost: 0 bytes in 0 blocks
==3689174==    still reachable: 101,279 bytes in 10 blocks
==3689174==         suppressed: 0 bytes in 0 blocks
==3689174==
==3689174== For lists of detected and suppressed errors, rerun with: -s
==3689174== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
make: *** [makefile:51: valgrind_load1] Segmentation fault (core dumped)
t30tvxxf

t30tvxxf1#

它为我在递归调用debug_fs()时用child == 0x01来分段错误。这对应于地址00000022处的值。
load_entries()中,你用fread(entries, sizeof(uintptr_t), num_entries, f);读取uintptr_t值的数组,但在debug_fs()中,你希望条目是struct inode *`的数组。你可能希望这些条目是node的索引:

struct inode* child = &node[node->entries[i]];

在此更改之后,您的代码不再segfaults:

Name: / Address: 0x7fff466edde0
/ (id 0) (address: 0x5651e2c4e480
Child: 0x5651e2c4e4a8
Name: kernel Address: 0x7fff466edda0
  kernel (id 1 size 20000b blocks 0 1 2 3 4 )
Child: 0x5651e2c4e4d0
Name: etc Address: 0x7fff466edda0
  etc (id 2) (address: 0x5651e2c4e4d0
Child: 0x5651e2c4e548
Name: (null) Address: 0x7fff466edd60
    (null) (id 0 size 0b blocks )

还有几个建议
1.写一个free_inodes(),如果malloc()load_indoes()中失败,则使用它。这意味着你要确保数组中当前位置之后的所有i-〉name和i-〉条目都是NULL。最简单的方法是使用calloc()而不是malloc()

void free_inodes(struct inode *inodes) {
    for(struct inode *i = inodes; i < inodes + NUM_INODES; i++) {
        free(i->name);
        free(i->entries);
    }
    free(inodes);
}

1.您可能希望更改load_entries()的接口,以便它可以告诉您文件中有多少个inode(而不是硬编码NUM_INODES)。

相关问题