1

Is there a function analogous to IsBadReadPtr in Unix? At least some functionalities of IsBadReadPtr? I want to write a procedure which would react if something bad happens to a process (like SIGSEGV) and recover some information. But I want to check the pointers to make sure that the data is not corrupt and see if they can be accessed safely. Otherwise the crash handling procedure itself will crash, thus becoming useless.

Any suggestions?

Deepu
  • 7,592
  • 4
  • 25
  • 47
StasM
  • 10,593
  • 6
  • 56
  • 103

4 Answers4

9

The usual way to do this on POSIX systems is to use the write() system call. It will return EFAULT in errno rather than raising a signal if the memory cannot be read:

int nullfd = open("/dev/random", O_WRONLY);

if (write(nullfd, pointer, size) < 0)
{
    /* Not OK */
}
close(nullfd);

(/dev/random is a good device to use for this on Linux, because it can be written by any user and will actually try to read the memory given. On OSes without /dev/random or where it isn't writeable, try /dev/null). Another alternative would be an anonymous pipe, but if you want to test a large region you'll need to regularly clear the reading end of the pipe.

caf
  • 233,326
  • 40
  • 323
  • 462
  • This solution doesn't work on Linux 3.8.7 ... write() ALWAYS returns success if 'fd' is /dev/null, even if 'pointer' is NULL. – etherice Apr 20 '13 at 18:24
  • On Linux, you can use `/dev/random` - I've updated the answer. – caf Apr 21 '13 at 00:03
  • Is it a POSIX thing or just a Linux thing for /dev/random write()'s to modify the entropy pool? If for some reason or on some platform it has no effect, then the kernel could choose to skip the write op and return success immediately like it does with /dev/null as an optimization. Without these kind of guarantees, I would still be nervous about that solution. – etherice Apr 24 '13 at 00:12
  • Also, it could be slow writing to /dev/random if it does modify the entropy pool. What I ended up using is a POSIX shared memory object via shm_open(). To keep the file/object size under control, I do an lseek(shm_fd, 0, SEEK_SET) whenever the approximated size surpasses some threshold. This is done (along w/ some other optimizations) to keep the amortized overhead limited to one system call per isMemoryBlockReadable(void*, size_t) call. – etherice Apr 24 '13 at 00:20
  • I'm not sure that `/dev/random` itself is in POSIX. The shared memory object method is also potentially a good idea, but note that POSIX leaves the effect of `write()` (and `lseek()`) on a shared memory object "unspecified". I suspect the most portable solution is a `pipe()` file descriptor, but that requires regular reading or closing/recreating of the pipe. – caf Apr 24 '13 at 01:44
  • Interesting on write/lseek being unspecified for POSIX shm. I still think it provides best combination of portability (even if not guaranteed by POSIX) and performance. You're right that using a pipe (or any "file" with guaranteed behavior for write()s/etc.) would be the most portable. (Or, if your app is single-threaded, you could avoid fd's entirely by using a SIGSEGV/SIGBUS signal handler and check/set/clear some global flags (e.g., g_inMemCheck and g_memViolationOccurred), but that's obviously not a generic/reusable "library type" solution.) – etherice Apr 25 '13 at 01:37
1

How can you do it?

You try to do it and then handle the error.

To do this, first you set up a sigsetjmp and a SIGSEGV signal handler. Then attempt to use the pointer. If it was a bad pointer then the SIGSEGV handler is called and you can jump to safety and report the error to the user.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
  • If I try to do it inside SIGSEGV handler it becomes kind of complex... Also can be SIGBUS. – StasM Jan 06 '11 at 05:21
0

You can never tell "whether a pointer can be accessed safely", on Windows or on Unix. But for some similar information on some unix platforms, check out cat /proc/self/maps.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • 1
    If I run under gdb, I can display a memory location and gdb would either display something or tell me `"Cannot access memory at address blah-blah"`. So it knows if I can or cannot access address blah-blah - I wonder how I could do the same from my program. – StasM Jan 06 '11 at 04:43
  • @StasM: gdb makes good guesses. Also it's accessing memory in *another* process via ptrace pokes, so it's okay if it crashes. – ephemient Jan 06 '11 at 05:05
0

I ran into the same issue trying to read a 'pixel' from a framebuffer while running Ubuntu from within a virtualbox. There seemed to be no secure way to check access without crashing or acutally hanging gdb. The suggestion made by StasM hinted me towards to following working 'local' solution using fork.

void *some_address;
int pid = fork();
if (pid== 0)
{
    someaddress[0] = some_address[0];
    _exit(123);
}
bool access_ok = true;
int status;
int result = waitpid(pid, &status, 0);
if (result == -1 || WIFEXITED(status) == 0 || WEXITSTATUS(status) != 123)
{
    access_ok = false;
}
Eric
  • 49
  • 4