3 ms·
You're gonna make me dig it out, ain't ya. I don't know where I put it, but I've written a macro and function that does this. Basically, given a pointer and a
by cryptonector 5y ago
You're gonna make me dig it out, ain't ya. I don't know where I put it, but I've written a macro and function that does this. Basically, given a pointer and allocation size, if it's smaller than 4KB, do nothing, if it's larger, loop for allocation size div 4KB touching a byte from one end of the allocation to the other. The tricky things are: determining in which direction the stack grows, and the page size (which, arguably, you can hard-code to 4KB) if you really don't want to hard-code 4KB.
You can determine stack growth direction by having one function call another with a pointer to a local variable in the former and then compare that to a pointer to a local variable in the latter. To do this correctly you have to cast to uintptr_t.
And, yes, pure C does not even assume a stack, much less a bounded stack. In pure C it's possible to have every call frame allocated on the heap, which means that assuming that they are allocated contiguously is not safe. Moreover, even with stacks, the run-time could allocate a second stack when the first is exhausted and push new call frames on the second rather than die. In pure C the only assumptions about limits have to do with the size of size_t. The real world intrudes though, and in practice all C run-times allocate call frames on bounded stacks.
- chrisseaton 5y agoNone of this is possible in a well-defined pure C program. Pages with special memory protection aren't a thing C knows anything about. That's the point - you can't do it without sacrificing portability.
- cryptonector 5y agoWhat I'm describing is portable. It may be unnecessary in C run-times that allocate call frames on the heap, but those aren't realistic C run-times.
- chrisseaton 5y agoSay I ran your code on a special C implementation that tracks all memory access and disallows it when you try to read from stack memory that doesn't contain a live object. That'd be a completely standards-compliant C implementation. Your code wouldn't run on it. Your code would not be portable to my standards-complaint implementation. Therefore your code is not portable.
- cryptonector 5y agoYou can almost certainly make it portable. After all, the allocation has a pointer, size, and type, and if it is at all an array, you could dereference every Nth element as needed, possibly with memcpy(), and avoid aliasing rules via casting to unsigned char *.
- chrisseaton 5y agoSo you're going to touch every byte of the memory, to check it's been successfully allocated. What happens when you access memory which has not been successfully allocated?
- cryptonector 5y ago> So you're going to touch every byte of the memory, to check it's been successfully allocated. Strictly less (not more than every 4KB), but, yes :) > What happens when you access memory which has not been successfully allocated? Portable C has finite size_t. Actual machines, virtual or otherwise, have finite resources. At some point you may run out of resources. With a dynamic stack allocation checker you'll fail with a segmentation fault when you run out. Without a dynamic stack allocation checker (but with dynamic stack allocations) you may well fail in random ways due to corruption of other stacks, heap, mmaps, etc. If your C run-time doesn't have stacks then a dynamic stack allocation checker may be pointless... unless your OS is over-committing memory, then it may cause failure to happen sooner than it might otherwise.
- chrisseaton 5y ago> you'll fail with a segmentation fault Who says you will? Nothing in the C specification says that.
- cryptonector 5y agoThe C specs assume unlimited (up to size_t) resources. Real life has no machines with 64-bit ISAs and 2^64 bytes' worth of resources. Real life isn't portable. Who knew. If there's no guard pages, no segmentation faults, no OOM killers, etc., then an allocation checker will cause failure in much the same kinds of undefined ways as not having the checker. A segmentation fault is what you can expect in real systems, and it's absolutely better than undefined behavior. You can do this portably, in C. It may not do you any good, and it may waste CPU cycles and memory bus usage. But it shouldn't harm. If the alternative is to not use alloca() or VLAs, and to make it so you can statically know your program's resource needs (which is very limiting, and not really attempted outside contexts where that such limitations are very strongly desired), then do that.
- deleted 5y ago[deleted]