错误,还是 valgrind/gcc bug?

发布于 2024-11-29 11:55:10 字数 1507 浏览 1 评论 0原文

当在以下程序上运行 valgrind 时,断言失败:

#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 中的错误?

When running valgrind on the following program the assertion fails:

#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 holds (bs + pageSize) at the faulting instruction, corresponding to (!!) in the code. However, si_addr does not match RAX in the ucontext of the signal handler (the value of RAX in the ucontext is equal to 'bs'). When (!!) is reexecuted after enabling writes RAX contains (bs). Executing outside valgrind works as expected.

Have I done something to cause undefined behaviour, or is it possible that this is a bug in GCC or valgrind?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

维持三分热 2024-12-06 11:55:10

如果您使用精确的异常,它将起作用。

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

此页面准确地描述了您要执行的操作: -))

如果您以巧妙的方式使用信号(例如,捕获 SIGSEGV,
修改页面状态并重新启动指令
),您可能
依赖于精确的例外。在这种情况下,您将需要使用
--vex-iropt-precise-memory-exns=yes

It will work if you use precise exceptions.

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

This page precisely describes what you are trying to do :-))

If you're using signals in clever ways (for example, catching SIGSEGV,
modifying page state and restarting the instruction
), you're probably
relying on precise exceptions. In this case, you will need to use
--vex-iropt-precise-memory-exns=yes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文