【问题标题】:How can I check whether a memory address is writable or not at runtime?如何在运行时检查内存地址是否可写?
【发布时间】:2013-01-21 06:35:41
【问题描述】:

如何在运行时检查内存地址是否可写?

例如,我想在下面的代码中实现 is_writable_address。有可能吗?

#include <stdio.h>

int is_writable_address(void *p) {
    // TODO
}

void func(char *s) {
    if (is_writable_address(s)) {
        *s = 'x';
    }
}

int main() {
    char *s1 = "foo";
    char s2[] = "bar";

    func(s1);
    func(s2);
    printf("%s, %s\n", s1, s2);
    return 0;
}

【问题讨论】:

标签: c unix operating-system


【解决方案1】:

我一般同意那些认为这是一个坏主意的人。

也就是说,鉴于问题具有 UNIX 标签,在类 UNIX 操作系统上执行此操作的经典方法是使用来自/dev/zeroread()

#include <fcntl.h>
#include <unistd.h>

int is_writeable(void *p)
{
    int fd = open("/dev/zero", O_RDONLY);
    int writeable;

    if (fd < 0)
        return -1; /* Should not happen */

    writeable = read(fd, p, 1) == 1;
    close(fd);

    return writeable;
}

【讨论】:

【解决方案2】:

这在技术上可能是可行的,但没有可移植的方式来做到这一点,而且永远没有必要这样做。如果您设法忘记了一个指针是否可写,那么还有很多您也不知道的更重要的细节,比如它指向什么,以及您的代码是否应该 写信还是不写。

【讨论】:

  • 是的,事实上在 C 中没有一种干净的可移植方式来执行此操作。这将取决于操作系统。如果你在 C++ 中,你可以尝试写入内存(在第一次读取并保存已经存在的内容之后,如果你覆盖它,你可以恢复它)。您可以将其包装在 try catch 中。如果你没有得到异常,看起来内存是可写的。但是有多危险!!您正在写入内存,显然您不知道那里有什么。谁知道你在覆盖什么!
  • 分段错误(访问冲突、内存错误等)是 CPU 异常,而不是 C++ 异常。它们不能被 try/catch 捕获;执行非法内存访问只会终止进程。
  • 请注意,您不能可移植地依赖它们不是 C++ 异常。 Windows 有 SEH,它会抛出异常以响应故障。这对你来说是未定义的行为......
  • 这样做可能有正当理由,例如如果您访问过度使用系统上的内存(这些天几乎所有内容),当系统无法将物理内存页面映射到您的虚拟地址时,您会收到总线错误。最好先测试地址,看看它是否可写,这样你就可以更优雅地失败。
猜你喜欢
  • 2020-07-30
  • 1970-01-01
  • 1970-01-01
  • 2012-11-10
  • 2014-11-27
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 2017-01-29
相关资源
最近更新 更多