This all started because I was complaining about some uninitialized pointer value causing me grief1 and someone (explicitly trolling) said they always check pointers using:
int fds[2] = { -1, -1};
pipe(fds);
if (write(fds[0], pointer_to_check, sizeof(intptr_t)) == -1) {
close(fds[0]);
close(fds[1]);
return not_valid;
} else {
close(fds[0]);
close(fds[1]);
return valid;
}In case it's not abundantly clear, you should never do this2, but of course the first thing I saw was the duplication of code responsible for managing resources, a reminder of how redundant and error-prone C can be.
A different formulation of this code might look like:
int rc, fds[2] = { -1, -1};
pipe(fds);
if (write(fds[0], pointer_to_check, sizeof(intptr_t)) == -1) {
rc = not_valid;
} else {
rc = valid;
}
close(fds[0]);
close(fds[1]);
return rc;This reduces duplication while sacrificing code locality. I still don't love it, but I feel like it's a safer style.
Really what I want is something like Swift's defer:
int fds[2] = { -1, -1};
pipe(fds);
defer {
close(fds[0]);
close(fds[1]);
}
if (write(fds[0], pointer_to_check, sizeof(intptr_t)) == -1) {
return not_valid;
} else {
return valid;
}Turned out it's not too heinous to hack together. Here it is.
Footnotes
-
as appealing as its promise is,
mmapis bad and you should never use it unless you truly need garbage collected shared memory between processes, in which case your life already sucks and I'm sorry.preadandpwritewill seterrnoinstead of crashing your process and are not nearly as slow as you think; you should stick with them until you can measure otherwise, at which point you should investigate doing your own paging because as I just saidmmapis dangerous and bad. ↩ -
If you have a problem with wild pointers then you also have much bigger problems that you should solve first. If you're just hacking away on code that will never run on someone else's computer you should try
mincoreormach_vm_read. ↩