3 ms·
The design might be fundamentally broken, but if so you're saying that even with an mmu, we can only have co-operative multitasking. That's not the promise of a
by e12e 9y ago
The design might be fundamentally broken, but if so you're saying that even with an mmu, we can only have co-operative multitasking. That's not the promise of a multi-user/multi-prosess system.
If "all programs are safe", we could just use the Amiga OS kernel and no longer need an mmu, or a similar design.
[ed: apparently windows NT takes steps to avoid this according to a sibling comment. Not clear, but I assume it implies a performance hit for certain heavy stack usage?]
- clarry 9y agoThere would be a performance hit, but that is likely to be insignificant. Apparently the stack check code touches every stack page. If performance were a concern (and I don't really think it is), it should be possible to reduce the impact by assuming a sufficiently large stack guard that the majority of functions with fixed size stack frames could never leap over. Then these functions wouldn't need any runtime checks. The only checking you'd have to do is on code that uses VLAs, alloca, or such, along with the few outlier functions that use ridiculously large fixed size buffers. I don't see why you should need to touch every page.
- geofft 9y agoI don't entirely follow what you're saying in your first sentence, but I'm going to try to respond to what I think you're saying. If I'm off base please let me know! 1. Memory-safe languages are about making sure that the programmer's intended behavior matches the actual behavior, that is, eliminating a class of bugs related to memory unsafety. They are a security scheme insofar as these bugs are security bugs, but they're not an interprocess security scheme. In particular, you can write a memory-safe debugger that goes and makes arbitrary modifications to other processes the OS gives it access to. You can even write a memory-safe program in Rust that goes and edits /proc/self/mem. But in these cases, the programmer is intending to mess with process memory directly, so the language isn't obligated to stop the programmer. It is obligated to stop the programmer from, say, overflowing a string and overwriting the return address. 2. It is certainly possible to design a memory-safe language that is usable for interprocess memory protection. Microsoft had a research OS called Singularity that did exactly this: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/osr2007_rethinkingsoftwarestack.pdf https://www.microsoft.com/en-us/research/wp-content/uploads/... But it's another step on top of memory safety. 3. Preemptive multitasking and protected memory aren't inherently related (although, yes, in the market, most cooperatively multitasked OSes lacked memory protection, and most OSes with memory protections were preemptively multitasked). You can have a preemptively multitasked system with no MMU at all; you just need to respond to timer interrupts and switch tasks.
- e12e 9y agoYou're right, I leapt over some points, and landed slightly outside the discussion - I guess I think of growing the stack and allocating heap memory as something the kernel should be the arbiter of - and that the api should never allow you to grow into your own (or another process') memory. I suppose it's fine to say mallloc will return memory, but it's up to the process to check if there are any overlaps - but that sounds a little crazy?
- caf 9y agoThat is basically how it works, with the caveat that if you want the kernel to arbitrate your stack expansion you must only expand by a page at a time (and that's what gcc's -fstack-check does). If you decrement your stack pointer by a large value and then offset it - which is essentially what's happening in these cases - the kernel can't arbitrate that because if the access lands in otherwise allocated memory it doesn't fault and so the kernel never sees the access at all.
- e12e 9y agoI meant that the equivalent for mallloc would be that if you allocate 1mb buffer and a 2mb buffer, the kernel might return a 2mb buffer overlapping your earlier 1mb buffer - and be all like: "you asked for 1, you asked for 2 - and you've got 2 - if you wanted 3, you should've asked for 3". Afaik mallloc doesn't work like that - it assumes that you want more memory (and can fail or succeed etc). I can see how the current stack/heap thing evolved - but I still think it's crazy :-)