内存映射固定位置的数组

时间:2014-10-31 04:38:17

标签: c valgrind mmap

要验证程序,我需要生成确定性地址跟踪。所以我使用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上尝试了不同的保护标志组合,但没有运气。我很感激任何帮助。

1 个答案:

答案 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保留区。