
Legitimate-Ish Use of Alloca() - ingve
https://nullprogram.com/blog/2019/10/28/
======
kazinator
You need alloca in virtual machines to allocate local variable frames, if you
have opted for using the native stack for doing so. These frames are dynamic;
their size comes from some field pulled from a function object. Alloca is also
useful in resuming stack-snapshot-based delimited continuations. These objects
have to be planted into the stack to work properly. They also have a variable
size: whatever it took to capture them up to their delimited prompt from.

Basically, C function calls are doing the equivalent of alloca all the time.
The size of stack needed by a function call is not known in advance. It may be
a constant in that particular function, but what function is called depends on
run-time tests, and indirect calls. (*fptr)(foo) could call one of fifty
possible functions, whose stack consumption ranges from 50 bytes to 50,000.
That's kind of like calling alloca with a random number between 50 and 50,000.
And like with alloca, there is no detection. C is not robust against the
problem of "no more room for the next stack frame"; it is undefined behavior.

The simplified idea that "all alloca is bad" comes from a parochial, in-the-
box thinking.

(Sure, alloca for, say, temporary storage for catenating strings that come
from "read a line of any length" routines, whose inputs are controlled by a
remote attacker, is undeniably bad. However, even without using alloca, we can
cause the problem that some input available to an attacker controls the depth
of some (non-tail-optimized) recursion.)

------
ioquatix
Interesting article, but I feel like the conclusion using `STACK_SIZE` doesn't
make any sense.

If you are willing to publish that in a public header, you will break any code
if your stack struct changes size. Like, I get the point of using
`alloca(stack_size())`... but I don't see why `alloca(STACK_SIZE)` is any
better than `struct stack my_stack;`.

~~~
saagarjha
How so? Wouldn’t you just recompile with the new stack size?

~~~
DougBTX
The idea with an ABI (an Application Binary Interface rather than an API) is
that there is no need to re-compile, existing binaries still work since the
binary interface stays the same.

~~~
jcelerier
Is that still relevant though (or rather, is the cost / benefit ratio of ABI
stability still worth it ?). My laptop from last year is able to bootstrap and
build a full yocto system from gcc to the kernel to glibc to X11 to Qt5 in ~15
hours.

~~~
OskarS
Of course it's still relevant. As long as dynamic loading is relevant, stable
ABIs are relevant.

If someone finds a security bug in OpenSSL (Heartbleed, for instance), you
only need a single update to the OpenSSL libs to fix every program that
dynamically link it. But that only works if you have a stable ABI: otherwise,
every single program would have to be recompiled to fix the bug.

~~~
jcelerier
> But that only works if you have a stable ABI: otherwise, every single
> program would have to be recompiled to fix the bug.

yes, and what I am saying is that in 2019, the cost of recompiling $everything
is quite low.

~~~
pjmlp
Not everyone has a top level computer, not everyone is an expert on rebuilding
distributions from scratch, not everything is available as source code to
build from, not every OS is a GNU/Linux clone.

~~~
jcelerier
> Not everyone has a top level computer, not everyone is an expert on
> rebuilding distributions from scratch

you aren't but your distro maintainer should be

> not everything is available as source code to build from,

and most software not available as source code actually do ship their
dependencies because it would be madness to suppose that there will never be
any ABI or API break at any point in the future

> not every OS is a GNU/Linux clone

GNU/Linux is actually the exception here - the two big others just ship and
replace the whole OS on every major update (and I've heard that this was the
case for minor windows update too nowadays, not sure how much this is true)

------
rom1v
Alsa-lib exposes such functions/macros, for example:

\- #define snd_pcm_info_alloca(ptr)

\- size_t snd_pcm_info_sizeof(void)

[https://www.alsa-project.org/alsa-doc/alsa-
lib/group___p_c_m...](https://www.alsa-project.org/alsa-doc/alsa-
lib/group___p_c_m___info.html)

------
enriquto
The real tragedy of the C language is that VLA are not implemented safely in
any known implementation. They are so natural to use! Any pair of malloc/free
on the same scope could be cleanly replaced by a single VLA declaration.

~~~
jpfr
All C compilers I know either have VLA or alloca. In one of my projects, a bit
of macro magic uses either VLA or alloca to generate a temporary array. Works
great! I don't have further requirements here.

Please explain what you mean by "safe" in this context.

~~~
enriquto
I mean a way to control for stack overflow. I would like to allocate very
large images as VLA, where the size is only known at runtime. If I malloc a
too large image, the systems asks for more memory or malloc fails. If I
declare a VLA too large, it fails silently in an unrelated part of my program
due to stack corruption.

~~~
devit
Correct implementations use stack probing (access one word for every page in
the allocation) to guarantee that a stack overflow happens immediately rather
than resulting in stack corruption.

~~~
enriquto
Alright, but that doesn't really solve anything, does it? It just makes the
problem easier to debug.

~~~
thenewnewguy
What's the problem, that the stack is capable of being overflowed? How do you
expect the C compiler to fix that?

~~~
enriquto
The stack is not a concept belonging to the C language definition, it is just
an implementation choice made by some compiler vendors (all that I know of).
The semantics for VLA are clear and very useful. I would certainly not expect
that the memory for VLA is implemented on the same stack as the function call
stack. My complain for C programming (what I called its "tragedy") is that no
compiler provides a mechanism for safely using all available memory via VLA.

Edit: you may answer: "use alloca then". But the syntax for alloca is not that
convenient, and the semantics are very different. A common use for VLA is to
declare a temporary array inside the body of a loop, this is not possible with
alloca.

------
dooglius
> Accessing a char value as if it were a different type just isn’t allowed.

Is this still bad if you have the proper alignment (by attribute or implicit
placement in a struct), or have it wrapped in a packed struct? There's a lot
of code that does this, e.g. overloading the definition of struct sockaddr.

~~~
gpderetta
sockaddr is problematic. Semi-recently glibc had to add compiler magic
(may_alias IIRC) to prevent breakage (posix says it has to work, so it is up
to the implementer to make it work).

