malloc()成功但分配的内存少于预期

时间:2013-10-15 08:53:04

标签: c memory-management malloc

我使用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

3 个答案:

答案 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 之外最简单的设置之一(不需要任何设置,但遗憾的是并不总是有效)