提问人:ph140 提问时间:3/28/2023 最后编辑:ph140 更新时间:3/28/2023 访问量:48
如何从结构体中获得正确的输出?从二进制文件加载信息后
How do I get the right output from the struct? After loading info from a binary file
问:
我正在尝试将数据从二进制文件读取到 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。接下来的四个是文件大小。接下来的四个是条目。
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)
答:
0赞
Allan Wind
3/28/2023
#1
它在第一个 print 语句的递归调用中为我分段错误,并且一旦您在使用前移动 NULL 检查:debug_fs()
child == 0x00
child == 0x01
printf("Name: %s Address: %p\n", node->name, &node);
if( node == NULL ) return;
对应于 address 的值,分别是第一个 。00000020
00000022
entries
inode
在你读取一个值数组,但你希望条目是一个 inode *' 的数组。您可能希望这些条目成为节点的索引:load_entries()
uintptr_t
fread(entries, sizeof(uintptr_t), num_entries, f);
debug_fs()
struct
struct inode* child = &node[node->entries[i]];
进行此更改后,代码不再段错误:
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 )
其他几点建议:
- 编写一个 如果失败,请在 中使用它。这意味着您要确保数组中当前位置之后的所有 i->name 和 i->entries 都是 NULL。最简单的方法是使用而不是:
free_inodes()
malloc()
load_indoes()
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);
}
- 您可能希望更改接口,以便它可以告诉您文件中有多少个 inode(而不是硬编码)。
load_entries()
NUM_INODES
下一个:C 语言中动态结构的内存分配
评论
struct inode
malloc()
name
xxd -r <<EOF > master_file_table <paste hexdump> EOF
获取二进制文件。