2011-08-14 77 views
2

当在下面的程序运行的valgrind断言失败:错误或valgrind/gcc错误?

#include <unistd.h> 
#include <sys/mman.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <stdint.h> 
#include <stdio.h> 
#include <wchar.h> 
#include <assert.h> 
#include <signal.h> 
#include <stdlib.h> 
#include <ucontext.h> 

static size_t pageSize = 4096; 

uint8_t *bs; 
static void sig(int num, 
    siginfo_t *info, void *unused) { 
    ucontext *p = (ucontext *)unused; 
    uint8_t *addr = (uint8_t *)info->si_addr; 
    wprintf(L"rax=%lx\n", p->uc_mcontext.gregs[REG_RAX]); 
    wprintf(L"addr=%lx\n", addr); 
    assert(mprotect(bs, pageSize*4, 
     PROT_READ | PROT_WRITE) == 0); 
} 


bool setsig() { 
    sigset_t mask; 
    struct sigaction sa; 

    if (sigemptyset(&mask)) 
     return false; 

    sa.sa_sigaction = sig; 
    sa.sa_mask = mask; 
    sa.sa_flags = SA_SIGINFO; 

    if (sigaction(SIGSEGV,&sa, NULL) != 0) 
     return false; 

    return true; 
} 

int main() { 
    assert(setsig()); 

    bs = (uint8_t *)mmap(NULL, pageSize*4, 
     PROT_READ, 
     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 
    assert(bs != MAP_FAILED); 

    bs[pageSize] = 3; // !! 
    assert(bs[pageSize] == 3); 

    return 0; 
} 

RAX成立(BS +的pageSize)在错误指令,对应于(!!)中的代码。但是,si_addr与信号处理程序的ucontext中的RAX不匹配(ucontext中的RAX值等于'bs')。在启用写入RAX包含(bs)后重新执行(!!)。按预期执行valgrind外部工作。

我做了一些事情会导致未定义的行为,或者这可能是GCC或valgrind中的错误吗?

+0

我在valgrind 3.6.1和svn的最新版本中得到了这个行为。 – user836336

+0

一个侧面说明不是问题得到解答:我意识到这是一个简单的测试,但是您不应该将带有副作用的代码作为参数提交给'assert'。如果使用-DNDEBUG进行编译,一切都会中断。另外'wprintf'在信号处理程序中调用不安全(参见[这里](https://www.securecoding.cert.org/confluence/display/seccode/SIG30-C.+Call+only+asynchronous-safe+functions + + +信号处理程序中))。 – user786653

+0

@ user786653:好点重新:断言。 – user836336

回答

6

如果您使用精确的例外,它将起作用。

valgrind --vex-iropt-precise-memory-exns=yes ./your_program 

This page恰恰说明你正在尝试做的:-))

如果您使用的是聪明的方式信号(例如,捕捉SIGSEGV, 修改页面状态并重新启动指令),你可能是 依靠准确的例外。在这种情况下,您需要使用 --vex-iropt-precise-memory-exns=yes

+0

非常感谢!对于不仔细阅读手册抱歉。:-) – user836336