6

How can I check whether a memory address is writable or not at runtime?

For example, I want to implement is_writable_address in following code. Is it possible?

#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;
}
Takayuki Sato
  • 1,023
  • 1
  • 14
  • 22
  • Given the inherently machine-dependent nature of compiled code, I don't see any way this would be possible. Moreover, I don't see any *reason* you would want to do this; I'm sure there are other ways to accomplish whatever it is you've set out to do. – Ricky Stewart Jan 21 '13 at 06:44
  • Linux has `mprotect` to set the memory protection but has has no direct way to query the memory protection state. Check out this question: http://stackoverflow.com/questions/3585641/how-to-get-the-memory-access-type-in-c-c-in-linux –  Jan 21 '13 at 06:44
  • possible duplicate of [Is there a better way than parsing /proc/self/maps to figure out memory protection?](http://stackoverflow.com/questions/269314/is-there-a-better-way-than-parsing-proc-self-maps-to-figure-out-memory-protecti) – alk Jan 21 '13 at 06:52
  • 3
    If you have to ask, then you're doing something wrong. – Raymond Chen Jan 21 '13 at 06:55
  • why not using `readelf` like functionality ? and check the readable-writable parts by parsing the ELF structure ? – Amir Naghizadeh Jan 21 '13 at 07:07

2 Answers2

8

I generally concur with those suggesting that this is a bad idea.

That said, and given that the question has the UNIX tag, the classic way to do this on UNIX-like operating systems is to use a read() from /dev/zero:

#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;
}
caf
  • 233,326
  • 40
  • 323
  • 462
  • I have seen that libunwind have a similar function: https://github.com/libunwind/libunwind/blob/master/src/x86_64/Ginit.c#L122, they use a pipe to read and then write again to check if an address is writable, I am just wondering why they use an additional write call, I think that read once is enough. – prehistoricpenguin Sep 06 '20 at 07:00
0

It may be technically possible, but there is no portable way to do so, and it should never be necessary to do so. If you've managed to lose track of whether a pointer is writable or not, there's a bunch of even more important details that you don't know either, like what it points to, and whether your code should be writing to it or not.

  • 1
    Yes to the fact there is not a clean portable way to do this in C. It would be operating system dependent. If you were in C++ you could try writing to the memory (after first reading and saving what's already there, so you can restore it if you overwrite it). You could wrap that in a try catch. If you don't get an exception, it looks like the memory is writable. But how dangerous!! You are writing to memory and apparently you don't know what's there. Who knows what you are overwriting! – DWright Jan 21 '13 at 07:05
  • 2
    Segmentation faults (access violations, memory errors, etc) are CPU exceptions, not C++ exceptions. They cannot be trapped by try/catch; performing an illegal memory access will simply terminate the process. –  Jan 21 '13 at 07:07
  • Note though that you can't portably *rely* on them not being C++ exceptions. Windows has SEH, which throws an exception in response to faults. That's undefined behavior for you... – Steve Jessop Jan 21 '13 at 10:04
  • 1
    There can be valid reasons to do this, e.g. if you access memory on overcommit systems (pretty much everything these days) you get a bus error when the system can't map a physical memory page to your virtual address. It can be nice to test the address first to see if it's writable so that you can fail more gracefully. – Eloff Apr 10 '15 at 15:21