1

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

3 回答 3

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));
于 2013-10-15T08:56:36.317 回答
4

这似乎有道理,

gdb 中的这个命令:

   p *(ino_table + 8000)

没有“将 ino_table 的内容打印偏移 8000 字节”。它说,“打印 ino_table 偏移 8000 个元素的内容”。

这意味着 gdb 的计算方式*(ino_table + 8000)与 C 相同,它为您提供了第 8000 个元素。这和说的一样p ino_table[8000]

以字节为单位,即sizeof(struct inode) * 8000. 除非 sizeof(struct inode) 为 1,否则这将超出范围。

在为元素数组分配空间时,通常会说需要多少个元素,但是您已经告诉 malloc() 获取 8192 字节。如果您想要 a 中的 8192 个元素struct inodeino_table您可以:

 struct inode * ino_table = malloc(8192 * sizeof *ino_table);

请注意,gdb 不会对您的数组/缓冲区进行绑定检查。如果您成功地做到p *(ino_table + 4205)了,那很可能超出了 的范围ino_table,并且可能指向其他地方的可用内存。当 gdb 最终出现错误时Cannot access memory at address 0x643a30,这意味着您现在正在尝试访问不存在的内存 - 即它根本没有映射到您的进程的地址空间。

于 2013-10-15T08:57:39.903 回答
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]- 的第 8000 个元素ino_table,除非您的 struct inode 定义为 1 字节大小,否则它将位于分配的内存之外。


更笼统地说:

如果你有一个指向类型 T 的指针 P,那么 P++ 会将存储在 P 中的地址增加 sizeof(T),而不是增加一个字节。


此外,而不是

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确保您获得空内存(在大多数实现中,通过为您提供指向系统的特殊写时复制归零内存页面的指针),以及返回对齐的内存sizeof(type)(malloc 通常也会返回对齐内存,但在 malloc 的情况下,它可能会对齐到最大的可对齐值)


由于在不同的答案中提到了边界检查:您可以查看 gcc mudflap扩展-它并不完全进行边界检查,而是进行许多其他与内存相关的事情,恕我直言是除了valgrind之外最容易设置的事情之一(不需要任何设置,但不幸的是并不总是有效)

于 2013-10-15T08:56:19.553 回答