要验证程序,我需要生成确定性地址跟踪。所以我使用mmap
在虚拟内存中的固定位置分配一个数组。
这就是我所拥有的:
#define PG_SIZE 4096
#define PG_START(_v) ((_v) & ~(unsigned long)(PG_SIZE-1))
// has to be aligned to page. otherwise it will be done for you.
#define ARRAY_ONE_BASE PG_START(0xffeffd000)
#define ARRAY_ONE_SIZE (4096 * 2 * sizeof(int))
unsigned long * allocateArray(unsigned long addr, size_t size) {
int stack_prot = PROT_READ | PROT_WRITE;
int flags = MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS;
unsigned long *m_map;
m_map = mmap((caddr_t)PG_START(addr), size, stack_prot, flags, -1, 0);
// fail if mmap faield
if (m_map == MAP_FAILED) {
perror("mmap failed");
abort();
}
printf("Base address of allocated variable: %li\n", m_map);
assert((void *)m_map == (void *)addr);
return m_map;
}
int main(int argc, char *argv[]) {
unsigned long *addrOne = allocateArray(ARRAY_ONE_BASE, ARRAY_ONE_SIZE);
}
如果我编译并运行上面的代码,它可以正常工作。但是,当我尝试运行valgrind
工具lackey
时,会出现分段错误。
命令:
gcc program.c
valgrind --read-var-info=yes --tool=lackey a.out
输出:
==28528== Lackey, an example Valgrind tool
==28528== Copyright (C) 2002-2013, and GNU GPL'd, by Nicholas Nethercote.
==28528== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==28528== Command: a.out
==28528==
==28528==
==28528== Process terminating with default action of signal 11 (SIGSEGV)
==28528== Bad permissions for mapped region at address 0x0
==28528== at 0x0: ???
==28528==
==28528== Counted 1 call to main()
==28528==
==28528== Jccs:
==28528== total: 22,338
==28528== taken: 9,947 ( 44%)
==28528==
==28528== Executed:
==28528== SBs entered: 21,937
==28528== SBs completed: 14,439
==28528== guest instrs: 120,810
==28528== IRStmts: 723,993
==28528==
==28528== Ratios:
==28528== guest instrs : SB entered = 55 : 10
==28528== IRStmts : SB entered = 330 : 10
==28528== IRStmts : guest instr = 59 : 10
==28528==
==28528== Exit code: 0
Segmentation fault (core dumped)
我在mmap上尝试了不同的保护标志组合,但没有运气。我很感激任何帮助。
答案 0 :(得分:2)
无法保证带有MAP_FIXED的mmap()始终有效。
http://pubs.opengroup.org/onlinepubs/007908799/xsh/mmap.html有:
当在flags参数中设置MAP_FIXED时,将通知实现,pa的值必须是addr。如果设置了MAP_FIXED,则mmap()可以返回MAP_FAILED并将errno设置为[EINVAL]。
和Linux手册页有:
MAP_FIXED
不要将addr解释为提示:将映射放在该地址的确切位置。 addr必须是页面大小的倍数。如果addr和len指定的内存区域与任何现有映射的页面重叠,则将丢弃现有映射的重叠部分。如果无法使用指定的地址,mmap()将失败。因为要求映射的固定地址不太便携,所以不鼓励使用此选项。
例如,我在Ubuntu 14.04 x64 上运行你的程序有类似的结果,但是在我的Ubuntu 14.04 x86 框中失败了(这很自然地考虑了地址本身) :
$ ./a.out
mmap failed: Cannot allocate memory
Aborted
此外,Valgrind将more restrictions放在MAP_FIXED:
上(第076行)
- 尝试将客户端的固定和提示映射放在请求的地址。在的任何地方都允许使用固定映射,但Valgrind保留的区域除外;客户端可以根据需要删除自己的映射。
然后我将程序中的ARRAY_ONE_BASE从0xffeffd000更改为0x10ffeffd000,并且它有效:
$ valgrind --read-var-info=yes --tool=lackey ./a.out
==6319== Lackey, an example Valgrind tool
==6319== Copyright (C) 2002-2013, and GNU GPL'd, by Nicholas Nethercote.
==6319== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==6319== Command: ./a.out
==6319==
Base address of allocated variable: 0x10ffeffd000
==6319==
==6319== Counted 1 call to main()
==6319==
==6319== Jccs:
==6319== total: 20,945
==6319== taken: 9,423 ( 44%)
==6319==
==6319== Executed:
==6319== SBs entered: 19,675
==6319== SBs completed: 12,655
==6319== guest instrs: 105,453
==6319== IRStmts: 614,550
==6319==
==6319== Ratios:
==6319== guest instrs : SB entered = 53 : 10
==6319== IRStmts : SB entered = 312 : 10
==6319== IRStmts : guest instr = 58 : 10
==6319==
==6319== Exit code: 0
我不是Valgrind或Linux地址布局的专家,但看起来你精心挑选的地址0xffeffd000恰好击中了一些Valgrind保留区。