我使用malloc来分配8192个字节的内存; malloc成功返回,但由于某种原因,我无法访问超过该内存块的4205字节的内存。
我也试过分配更大的内存块(即8192 * 2),但仍然没有运气,只有前4205个内存可以访问:(
以下是部分代码:
int num_ino = 256;
struct inode * ino_table = malloc(8192);
assert(ino_table);
for(int i = 0; i < num_ino; i ++){
printf("pre core dump %d\n", i);
memcpy(ino_table + i * sizeof(struct inode), &inotable[i], sizeof(struct inode));
}
以下是gdb中发生的事情:
Breakpoint 1, unixfilesystem_init (dfd=3) at unixfilesystem.c:54
54 assert(ino_table);
(gdb) p *(ino_table)
$1 = {i_mode = 0, i_nlink = 0 '\000', i_uid = 0 '\000', i_gid = 0 '\000', i_size0 = 0 '\000', i_size1 = 0, i_addr = {0, 0, 0, 0, 0, 0, 0, 0},
i_atime = {0, 0}, i_mtime = {0, 0}}
(gdb) p *(ino_table + 4205)
$2 = {i_mode = 0, i_nlink = 0 '\000', i_uid = 0 '\000', i_gid = 0 '\000', i_size0 = 0 '\000', i_size1 = 0, i_addr = {0, 0, 0, 0, 0, 0, 0, 0},
i_atime = {0, 0}, i_mtime = {0, 0}}
(gdb) p *(ino_table + 8000)
Cannot access memory at address 0x643a30
(gdb) p *(ino_table + 4206)
Cannot access memory at address 0x625ff0
答案 0 :(得分:6)
在ino_table
上执行指针运算时,单位为sizeof(struct inode)
,而不是字节。
因此,
ino_table + i * sizeof(struct inode)
应该成为
ino_table + i
最后,我会改变malloc()
,如此:
struct inode * ino_table = malloc(num_ino * sizeof(struct inode));
答案 1 :(得分:4)
这似乎很合理,
gdb中的此命令:
p *(ino_table + 8000)
不说“打印ino_table偏移量的内容为8000字节”。它说,“打印ino_table的内容偏移8000个元素”。
这意味着gdb就像C一样评估*(ino_table + 8000)
,它为你提供了第8000个元素。
这与说p ino_table[8000]
相同。
以字节为单位,即sizeof(struct inode) * 8000
。除非sizeof(struct inode)为1,否则这将超出范围。
为元素数组分配空间时,通常会说需要多少元素,但是你已经告诉malloc()获得8192个字节。
如果您想要struct inode
中的ino_table
的8192个元素,您可以执行以下操作:
struct inode * ino_table = malloc(8192 * sizeof *ino_table);
请注意,gdb不会对数组/缓冲区进行绑定检查。如果你能成功p *(ino_table + 4205)
,那么ino_table
很可能会超出界限,可能会指向其他地方的可用内存。当gdb最终与Cannot access memory at address 0x643a30
出错时,这意味着您现在正在尝试访问不存在的内存 - 即它根本没有映射到您的进程的地址空间。
答案 2 :(得分:3)
你的问题很可能是指针运算。
ino_table + i * sizeof(struct inode)
很可能不是你想要的,但是
ino_table + i
由于指针算术ino_table + i
已经在做
((char *)ino_table) + i * sizeof(struct inode)
同样适用于gdb,其中ino_table + 8000
引用&ino_table[8000]
- ino_table
的第8000个元素,除非你的struct inode定义为1个字节,否则它将是在分配的内存之外。
更一般地说:
如果你有一个指向类型T的指针P,那么P ++会将存储在P中的地址增加sizeof(T),而不是增加一个字节。 < / p>
此外,而不是
ino_table + i
你可以做到
&ino_table[i]
这是很多人的首选(我个人并不在乎),因为通过一个元素增加i
来增加访问地址,而不是一个字节。
对于你可以做的malloc
malloc(number_of_elements * sizeof(type))
- 不要担心性能差异或代码大小,因为当number_of_elements不变时,表达式应该优化为一个常数。
或者,如果你想要特别小心和/或不知道你是否会访问你没有写过的部分,你可以使用:
calloc(number_of_elements, sizeof(type))
与malloc
的区别在于calloc
确保您获得无效内存(在大多数实现中,通过为您提供指向特殊 copy-on-write 归零内存的指针系统的页面),以及返回与sizeof(type)
对齐的内存(malloc通常也会返回对齐的内存,但在malloc的情况下,它可能会与最大的可对齐值对齐)
在另一个答案中提到了边界检查:你可以看看gcc mudflap 扩展 - 它不完全是边界检查,但是许多其他与内存有关的东西,恕我直言除了 valgrind 之外最简单的设置之一(不需要任何设置,但遗憾的是并不总是有效)