Live data from Hacker News

Allocating on the Stack

go.dev

21–30 of 59 posts

Re: Allocating on the Stack

#21

Earlier quoted context omitted.

alloca() is super useful, but it's also quite dangerous because you can easily overflow the stack. The obvious issue is that you can't know how much space is left on the stack, so you basically have to guess and pick an arbitrary "safe" size limit. This gets even more tricky when functions may be called recursively. The more subtle issue is that the stack memory returned by alloca() has function scope and therefore y…

> The obvious issue is that you can't know how much space is left on the stack [...] Oh, huh. I've never actually tried it, but I always assumed it would be possible to calculate this, at least for a given OS / arch. You just need 3 quantities, right? `remaining_stack_space = $stack_address - $rsp - $system_stack_size`. But I guess there's no API for a program to get its own stack address unless it has access to `/pr…

If your API includes inline assembly, then it's trivial. Go's internals would need it to swap stacks like it does. But I doubt any of that is exposed at the language level.

Re: Allocating on the Stack

#22
post #19

Earlier quoted context omitted.

alloca() is super useful, but it's also quite dangerous because you can easily overflow the stack. The obvious issue is that you can't know how much space is left on the stack, so you basically have to guess and pick an arbitrary "safe" size limit. This gets even more tricky when functions may be called recursively. The more subtle issue is that the stack memory returned by alloca() has function scope and therefore y…

If you have well defined boundaries, you can move the stack to an arbitrarily large chunk of memory before the recursive call and restore it to the system stack upon completion.

And if you never do reach completion, you can just garbage collect that chunk. AKA "Cheney on the MTA": https://dl.acm.org/doi/10.1145/214448.214454

Re: Allocating on the Stack

#23

Earlier quoted context omitted.

alloca() is super useful, but it's also quite dangerous because you can easily overflow the stack. The obvious issue is that you can't know how much space is left on the stack, so you basically have to guess and pick an arbitrary "safe" size limit. This gets even more tricky when functions may be called recursively. The more subtle issue is that the stack memory returned by alloca() has function scope and therefore y…

> The obvious issue is that you can't know how much space is left on the stack [...] Oh, huh. I've never actually tried it, but I always assumed it would be possible to calculate this, at least for a given OS / arch. You just need 3 quantities, right? `remaining_stack_space = $stack_address - $rsp - $system_stack_size`. But I guess there's no API for a program to get its own stack address unless it has access to `/pr…

> $system_stack_size

Does such thing even exist? And non-64 bit platforms the address space is small enough that with several threads of execution you may just be unable to grow your stack even up to $system_stack_size because it'd bump into something else.

Re: Allocating on the Stack

#25

This article is about Go, but I wonder how many C/C++ developers realize that you've always had the ability to allocate on the stack using alloca() rather than malloc(). Of course use cases are limited (variable length buffers/strings, etc) since the lifetime of anything on the stack has to match the lifetime of the stack frame (i.e the calling function), but it's super fast since it's just bumping up the stack point…

It becames super slow when you bump that pointer into a page that's missing from the TLB.

Re: Allocating on the Stack

#26

Earlier quoted context omitted.

> The obvious issue is that you can't know how much space is left on the stack [...] Oh, huh. I've never actually tried it, but I always assumed it would be possible to calculate this, at least for a given OS / arch. You just need 3 quantities, right? `remaining_stack_space = $stack_address - $rsp - $system_stack_size`. But I guess there's no API for a program to get its own stack address unless it has access to `/pr…

> $system_stack_size Does such thing even exist? And non-64 bit platforms the address space is small enough that with several threads of execution you may just be unable to grow your stack even up to $system_stack_size because it'd bump into something else.

> Does such thing even exist?

AFAIK no. There are default stack sizes, but they're just that, defaults, and they can vary on the same system: main thread stacks are generally 8MiB (except for Windows where it's just 1) but the size of ancillary stacks is much smaller everywhere but on linux using glibc.

It should be possible to get the stack root and size using `pthread_getattr_np`, but I don't know if there's anyone bothering with that, and it's a glibc extension.

Re: Allocating on the Stack

#27
post #25

This article is about Go, but I wonder how many C/C++ developers realize that you've always had the ability to allocate on the stack using alloca() rather than malloc(). Of course use cases are limited (variable length buffers/strings, etc) since the lifetime of anything on the stack has to match the lifetime of the stack frame (i.e the calling function), but it's super fast since it's just bumping up the stack point…

It becames super slow when you bump that pointer into a page that's missing from the TLB.

A TLB miss could happen when executing the next statement in your program. It's not something you have a lot of control over, and doesn't change the fact that allocating from the stack (when an option) is going to be faster than allocating from the heap.

Re: Allocating on the Stack

#28
post #20

Nice! That's (seems) so simple yet also so very effective. Shouldn't other memory-managed languages be able to profit from this as well?

C# has `stackalloc`

But that requires an explicit declaration and isn't done automatically under the hood, or am I missing something?

Re: Allocating on the Stack

#29

Earlier quoted context omitted.

> $system_stack_size Does such thing even exist? And non-64 bit platforms the address space is small enough that with several threads of execution you may just be unable to grow your stack even up to $system_stack_size because it'd bump into something else.

> Does such thing even exist? AFAIK no. There are default stack sizes, but they're just that, defaults, and they can vary on the same system: main thread stacks are generally 8MiB (except for Windows where it's just 1) but the size of ancillary stacks is much smaller everywhere but on linux using glibc. It should be possible to get the stack root and size using `pthread_getattr_np`, but I don't know if there's anyone…

.NET bothers with it, to support RuntimeHelpers.EnsureSufficientExecutionStack [1] and other things. See the pthreads calls used to here [2].

[1]: https://learn.microsoft.com/en-us/dotnet/api/system.runtime....

[2]: https://github.com/dotnet/runtime/blob/b6a3e784f0bb418fd2fa7...

Re: Allocating on the Stack

#30
post #25

Earlier quoted context omitted.

It becames super slow when you bump that pointer into a page that's missing from the TLB.

A TLB miss could happen when executing the next statement in your program. It's not something you have a lot of control over, and doesn't change the fact that allocating from the stack (when an option) is going to be faster than allocating from the heap.

So you don't allocate left and right, be it stack or heap.

It's all useless though unless you control the hardware. If you don't, you might as well prlimit --stack=unlimited and have at it.

Post reply on HN