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,
mmap
is 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.pread
andpwrite
will seterrno
instead 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 saidmmap
is 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
mincore
ormach_vm_read
. ↩