2011-08-14 106 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