3 ms·
The 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
by cryptonector 5y ago
The 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.
- Joker_vD 5y ago> A segmentation fault is what you can expect in real systems, Nope. Just today I've seen a stack corruption bug that instead of producing a segmentation fault caused the process to go into uninterruptible sleep, somehow.
- chrisseaton 5y agoYou're saying 'if run on a system that does things in a way I expect then it works' but the point of the article is 'but what about if you want to run on a system that's not as you expect and you want to run pure C'. We all know what you're saying works in practice on most machines. But it's not pure C and it's not portable if you follow the spec.
- cryptonector 5y agoIt's portably assuming that you can cast an allocation's pointer to a pointer to unsigned char. It's like assuming you can memset(), since that's effectively what it's doing. In the absence of memory over-commit, this will have no effect beyond wasting resources. In the presence of over-commit -bounded stacks resemble memory over-commitment!- it will have the effect of committing the memory OR failing in whatever way the machine fails when resources are exhausted. However, in the latter case, and when the machine uses stacks for C function calls, the failure will be defined by the machine rather than undefined (due to memory corruption). Also, in the absence of stacks, there's no "direction in which the stack grows", and any attempt to determine that direction will yield a nonsensical result, but doing memset() in one direction or the other will also then be equivalent anyways. EDIT: There is one non-portable thing here: the assumption that machines are more limited than size_t implies. However, that's a distinction without a difference for any 64-bit ABIs or larger because all such machines must be more limited than size_t implies. That there is any failure mode when resources are exhausted is a non-portable assumption is uselessly true. Not being able to assume defined resource exhaustion failure modes would be destructive -- that the C spec does not is irrelevant.
- khrbtxyz 5y agodetermine 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. This is undefined behavior. See n1570.pdf, Annex J page 560, J.2 Undefined behavior Pointers that do not point to the same aggregate or union (nor just beyond the same array object) are compared using relational operators (6.5.8).
- cryptonector 5y agoComparing the uintptr_t cast of two disparate pointers is not undefined behavior. A comparison may not yield a portable result because the integer representation of pointers may not be as plain memory addresses. So such a simplistic stack growth detector may get the wrong answer, but it's not undefined behavior: char stack_grows_up(uintptr_t callers_local) { char my_local = (uintptr_t)&my_local > callers_local; return my_local; } EDIT: Ah, and uintptr_t is an optional type. If the platform doesn't have it (e.g., because it's a segmented memory architecture) then this won't work, so it's not portable, but aside from that it's not undefined behavior, it's just that the computation of stack growth direction may well be wrong.