5 ms·
Ok, I’ve looked but failed - where is there an example of what a VLA is?
by chris_wot 8y ago
Ok, I’ve looked but failed - where is there an example of what a VLA is?
- nwmcsween 8y agoint foo[n] where n is variable and cannot be inferred at compile time.
- asveikau 8y agovoid foo(int n) { int m[n]; } The downside is if n is large you use a lot of stack, but you wouldn't notice if it's mostly called with low values. So a bit of a ticking time bomb. I guess if you have a really large n, like more than a few pages worth, then certain values of m[i] might wind up in some other page allocation where it shouldn't.... I seem to recall a vulnerability like this a year or two ago. (Normally a stack can grow on a page fault by hitting a guard page, but if the n above is absurdly large...)
- krzyk 8y agoOK, so what's the difference between that and malloc'ing a too big value? Same issue, you just need larger values. In both cases you need a guard.
- notacoward 8y agoThere's a huge difference in stack vs. heap allocations. Stack space might be effectively infinite in the basic user-space world, but not in any environment using green threads and certainly not in the kernel. In the Linux kernel this is made far worse by the fact that each task's stack sits right above the task structure itself, so a huge allocation might smash the task structure or the next task's stack. The latter is exactly what I had to debug a couple of jobs ago, and it was one of the more difficult debugging journeys of my long career (it was quite sporadic and manifested as hard hangs). VLAs make that kind of scenario much more likely. Being able to check the length before a potentially disastrous allocation is cumbersome, but safer.
- deleted 8y ago[deleted]
- rcxdude 8y agoThere's no way to return an error from a VLA allocation, and also within C you have no standard way of knowing how much is safe to allocate on the stack (and in fact it may not be possible to know).
- craftyguy 8y agoSo adding a if (n > MAX){ return; } Would not help?
- benchaney 8y agoChoosing an appropriate value for MAX could potentially be quite difficult.
- olliej 8y agoAs @benchaney said you have to choose an appropriate guard. But the issues with VLAs are many * the code is bigger, and people say is meaningfully slower * super easy to accidentally blow the stack - in kernel land that is probably going to end in a panic * using vLAs used to disable stack canaries for those frames, not sure if it still does For a lot of cases where you are truly going to need variable length you’re unlikely to be penalised heavily by a heap allocation due to the relative cost of the operations.
- jcelerier 8y ago> meaningfully slower really ? there's a difference but unless you keep allocating in a hot-loop this should hardly ever have observable costs : https://gcc.godbolt.org/z/SN9Ois https://gcc.godbolt.org/z/SN9Ois
- pjmlp 8y agoYes there is a talk done by Google at Linux Kernel Security Summit 2018 about it.
- jabl 8y agoThe problem is with how to access other variables on the stack. Usually the compiler uses an offset from the stack pointer, which without VLA's is known at compile time. However, if you have VLA's, you might need a calculation at runtime to figure out where that variable is stored. Or maybe the offset from the frame pointer is known statically, but then you can't do the "omit frame pointer" optimization and you thus waste a register. Or if you have a variable that is between two VLA's, then you need a runtime calculation regardless.
- tropo 8y agoMaking that a uint8_t would solve the problem. Non-kernel code (with a normal stack) could also make it a uint16_t.
- kevin_thibedeau 8y agoA stack can readily be less than 256 bytes.
- asveikau 8y agoI am not sure restricting the type of the size parameter makes VLAs a good idea if such a constraint is necessary. It seems brittle and too subtle. Will future readers get that this is the reason for the type choice? Aren't you one refactor away from making it effectively unbounded again? (I suppose a typedef and a comment can make the choice seem more explicit.) Of course whether any of this matters will depend on the specifics of the matter, kernel code being the most conservative by necessity.
- vlovich123 8y agoI'm not sure how a restriction would work. The kernel stack is 16kb (meaning uint16_t is already unsafe) & you don't actually know where in the stack you are when creating the VLA so even if you did restrict yourself to uint8_t that doesn't protect you in any way.
- tropo 8y agoYou're no less protected than you are when you call a function. Nothing ensures that a function can safely be called. uint8_t is effective protection, given the normal assumption of a stack with 4096 to 16384 bytes of space and a call stack that isn't insane. If you wish to make a formal proof of correctness, feel free to make worst-case assumptions.
- deleted 8y ago[deleted]