On 17/01/2025 03:22, Waldek Hebisch wrote:
David Brown <david.brown@hesbynett.no> wrote:
On 16/01/2025 17:46, Waldek Hebisch wrote:
David Brown <david.brown@hesbynett.no> wrote:
On 16/01/2025 13:35, Michael S wrote:
On Thu, 16 Jan 2025 12:36:45 +0100
David Brown <david.brown@hesbynett.no> wrote:
>
On 15/01/2025 21:59, Thomas Koenig wrote:
Michael S <already5chosen@yahoo.com> schrieb:
On Wed, 15 Jan 2025 18:00:34 -0000 (UTC)
Thomas Koenig <tkoenig@netcologne.de> wrote:
>
As you can guess, in kernel drivers VLA are unwelcome.
>
I can imagine that they are - but I really don't understand why. I've
never understood why people think there is something "dangerous" about
VLAs, or why they think using heap allocations is somehow "safer".
>
VLA normally allocate on the stack. Which at first glance look
great. But once one realize how small are stacks in modern
systems (compared to whole memory), this no longer looks good.
Basically, to use VLA one needs rather small bound on maximal
size of array.
>
Sure.
>
Given such bound always allocating maximal
size is simpler. Without _small_ bound on size heap is
safer, as it is desined to handle also big allocations.
>
You don't allocate anything in a VLA without knowing the bounds and
being sure it is appropriate to put on the stack. You don't allocate
anything on the heap without knowing the bounds and being sure it is
appropriate. There's no fundamental difference - it's just the cut-off
point that is different.
Well, AFAICS VLA-s may get allocated on function entry.
It could be allocated as soon as the size is known, yes.
In such
case caller have to check for allocation size, which spreads
allocation related code between caller and called function.
It is not about allocation sizes - it's about knowing the data you are dealing with, and sanitising unknown data.
In the very rough example I gave of string formatting or manipulation, you might be getting the strings in from outside - command line parameters, database entries, wildcard directory searches, etc. You sanity check the data when it comes in - regardless of whether or not you plan to allocate memory (stack or heap) for copying them. Now you know that the sizes are reasonable, you can allocate VLAs (or use alloca, or use malloc) without extra worries.
I am not suggesting you should have some kind of rule to check sizes just before every VLA declaration - I am suggesting that when you know the size is reasonable and safe, then using a VLA is reasonable and safe.
In case of 'malloc' one can simply check return value.
Drivel.
That's a myth that originated in the days of K&R C.
It is certainly true that if malloc returns 0, your allocation has failed. There are a few - but only a very few - circumstances where that is something that can realistically happen in code that is doing its job properly. Typically that would be in resource-constrainted systems where you might have some unusual circumstances causing overload.
But generally (and this means there will be exceptions), checking for null returns from malloc is :
a) Never properly tested, and often results in leaked resources or other problems;
b) Totally unrealistic in any real-world use of the code;
c) Treated as though it is a divine duty that must always be done ritually and religiously;
d) Treated as though it magically makes the code safe, correct and reliable.
Hopefully you can see that these points are self-contradictory.
If you try to call malloc with a size that is unreasonable for the circumstances, all kinds of bad things can happen /despite/ a non-null return value. What goes wrong can depend on many factors, including the OS, the malloc library, the size, the system setup, and what you do with the returned pointer. Simply /trying/ to run malloc with a bad size may, on some systems, lead to the OS trying to free up as much memory as it can in order to accommodate your request - whether malloc ends up returning null or not. Or maybe the request is done in with lazy allocations - you asked for 100 TB of memory and you got a pointer back, and things will only go wrong when you start using the virtual space.
Remember, from the point of view of people using the computer, having the OS push lots of stuff out of memory is tantamount to a broken system. A program that has runaway memory usage causes great frustration, and often leads to users doing a hard reset. And all the time, the malloc() calls have returned a non-null value.
So what does all that mean? It means you do /not/ blindly call malloc(), check for a null result, and think that's all good. It means you be sure you know what sizes you are asking for /before/ you call malloc - probably long before you get to the bit of code that actually calls malloc(). It means you look /before/ you leap - you don't "just go for it" and hope that you can figure out what went wrong from the debris left at the crash site.
And if you are in doubt - maybe you are pushing the target system to the limits, or have a program that demands more memory than many systems might have - you check in advance to see if the memory will be easily available. Such checks will be OS specific, of course.
(I'm sure some people will now be thinking "you should have used ulimit", or "don't enable swap", or "that's the fault of over-commit". That would all be missing the point. You can of course use such tools as a way of making sure your sizes are reasonable - it's up to the developer to decide how to handle such checks and controls. But checking the return of malloc is so far from being sufficient that it is basically useless in most circumstances.)
It is /exactly/ the same for VLAs (or alloca).
The limits for what sizes are "reasonable" will, of course, be smaller for stack allocations than for heap allocations. But that's all target dependent anyway - for the systems I typically work with, the limit for "reasonable" heap allocations is orders of magnitude smaller than "reasonable" stack allocations on desktops.
In fact,
in many programs simple wrapper that exits in case of allocation
failure is enough (if application can not do its work without
memory and there is no memory, then there is no point in continuing
execution).
Have you ever seen that happening in real life? Have you ever even known such code to be properly tested?
Don't get me wrong - a wrapper like this can be a good idea. But it's like an electrical fuse - it's a last resort, and only triggers if something has gone badly wrong. When you see a great music system with a 10 kW amplifier, you check if your house electrical system can handle that /before/ you buy it. You don't buy it, plug it in and rely on the fusebox to keep your house from burning down - even though you want the fuse there as a failsafe. For the most part, if malloc ever returns 0, the problem lies before malloc is called.
(Sorry for the rant - "my code is safe because I check the result of malloc" is one of these misconceptions that really annoy me.)