alloca() is hard...
-
Prelude: For the blissfully unaware,
alloca()
in C is a non-standard funciton akin tomalloc()
that allocates memory from the local stack, rather than the global heap (which is whatmalloc()
does) and thus gets automatically freed when the function in which it is called exits.Its use is generally frowned upon.
Which leads to a link where someone is removing attempts to be platform agnostic:
http://marc.info/?l=glibc-alpha&m=149788910605529&w=2 which, in part, reads...
diff --git a/intl/dcigettext.c b/intl/dcigettext.c index 0e79b1f..d778d19 100644 --- a/intl/dcigettext.c +++ b/intl/dcigettext.c @@ -27,28 +27,6 @@ #include <sys/types.h> -#ifdef __GNUC__ -# define alloca __builtin_alloca -# define HAVE_ALLOCA 1 -#else -# ifdef _MSC_VER -# include <malloc.h> -# define alloca _alloca -# else -# if defined HAVE_ALLOCA_H || defined _LIBC -# include <alloca.h> -# else -# ifdef _AIX - #pragma alloca -# else -# ifndef alloca -char *alloca (); -# endif -# endif -# endif -# endif -#endif - #include <errno.h> #ifndef errno
-
@PJH said in alloca() is hard...:
Its use is generally frowned upon.
Why?
Other than "C developers are fuckwits who hate the very idea of anything even remotely helpful", I mean.
-
That's pretty typical c boilerplate to account for differences in various platforms. I've seen worse.
It sounds like the person just replaced the only-sometimes-supported alloca with malloc/free, hooray for the lowest common denominator
-
@weng two reasons that I've found...
- It's not actually a Standard(tm) function
- Failure to allocate memory (e.g. trying for too much and corrupting the stack) results in undefined behaviour.
-
@PJH said in alloca() is hard...:
@weng two reasons that I've found...
- It's not actually a Standard(tm) function
- Failure to allocate memory (e.g. trying for too much and corrupting the stack) results in undefined behaviour.
- SO STANDARDIZE SOMETHING SIMILAR.
- SO DEFINE IT WHEN YOU STANDARDIZE SOMETHING SIMILAR.
Fucking C people.
-
@weng said in alloca() is hard...:
Fucking C people.
Do realise that it's not the users of the language that cause these problems, it's the people in Ivory Towers that inflict it on us...
-
Read the title as "cloaca()"
-
@pjh said in alloca() is hard...:
Do realise that it's not the users of the language that cause these problems, it's the people in Ivory Towers that inflict it on us...
Nothing to do with me! Those of us actually in Ivory Towers use much less innocuous stuff!
-
@tsaukpaetra said in alloca() is hard...:
Read the title as "cloaca()"
Not too far from the truth having seen some code at work....
-
@weng said in alloca() is hard...:
SO DEFINE IT WHEN YOU STANDARDIZE SOMETHING SIMILAR.
C99 variable length arrays.
Which some crazy crack-addled motherfucker made optional in C11. Jerkwad DNA wastes!
-
@weng said in alloca() is hard...:
- SO DEFINE IT WHEN YOU STANDARDIZE SOMETHING SIMILAR.
C programmers [who frown upon the use of alloca] consider stack space to be a rare and valuable resource. For them, when
malloc
fails, at least it returnsNULL
, but when there wasn't enough space on the stack [andalloca
should have failed], it's easy to end up past the guard page which would otherwise have caused it to grow and overwrite something really important (heap if not code, depending on the OS and other stuff aforementioned C programmers care about).Because of the stuff above it may turn out be inefficient or maybe even impossible to implement any sensibly predictable behaviour you would expect from the standard on some platforms C programmers are fond of. Same with C99 VLAs (and that's why they were made optional in C11, AFAIK).
See also: how memory layout and access bits in OpenBSD prevent some of that stuff, but not all of it.
-
@aitap It's really not that hard to check - when implementing alloca in some platform - whether you're overflowing the stack - you can read every <page size> bytes of the "allocated" memory in sequence to ensure it doesn't have a guard page. (This also needs to be done if you have a function with more than <page size> bytes in its stack frame, so it's hardly new territory.)
-
@tsaukpaetra said in alloca() is hard...:
Read the title as "cloaca()"
Pervert. I read it as @accalia...
-
@anotherusername said in alloca() is hard...:
@tsaukpaetra said in alloca() is hard...:
Read the title as "cloaca()"
Pervert. I read it as @accalia...
BLEGUH! it's C! i wouldn't touch it with a ten foot pole!!
-
@createdtodislikethis but that would cost a few picoseconds, we can't have that
-
@weng said in alloca() is hard...:
@PJH said in alloca() is hard...:
@weng two reasons that I've found...
- It's not actually a Standard(tm) function
- Failure to allocate memory (e.g. trying for too much and corrupting the stack) results in undefined behaviour.
- SO STANDARDIZE SOMETHING SIMILAR.
- SO DEFINE IT WHEN YOU STANDARDIZE SOMETHING SIMILAR.
Fucking C people.
"We're working on it. Should be ready for the upcoming 2040 version of the standard" - C people
-
@weng said in alloca() is hard...:
Fucking C people.
-
@createdtodislikethis the problem is, if you run out of stack space, handling it is also very likely to run out of stack space.
-
@gąska not if it's caused by an alloca requesting 1TB
-
@wharrgarbl allocating 1TB on stack is wrong, so making idiots unable to do so is good.
-
@gąska No. If you're the programmer who has a problem avoiding being an idiot, use something other than C. C is a language for non-idiots; it punishes the dumb and ill-thought-out (sometimes by letting their code work for a while before crashing in flames).
-
@dkf said in alloca() is hard...:
@gąska No. If you're the programmer who has a problem avoiding being an idiot, use something other than C. C is a language for non-idiots; it punishes the dumb and ill-thought-out (sometimes by letting their code work for a while before crashing in flames).
C is an excellent language if you like periodically pulling your hair out asking yourself how that broken piece of code even worked in the first place.
-
@pleegwat said in alloca() is hard...:
C is an excellent language if you like periodically pulling your hair out asking yourself how that broken piece of code even worked in the first place.
Like JavaScript
-
@dkf said in alloca() is hard...:
C is a language for non-idiots; it punishes the dumb and ill-thought-out (sometimes by letting their code work for a while before crashing in flames).
It also punish the suckers that write perfectly cromulent programs in wtf-platforms with badly implemented C libraries.
va_start your parameter list twice and the memory is corrupted, but only if you're not connected to the debugger.
-
@wharrgarbl said in alloca() is hard...:
va_start your parameter list twice and the memory is corrupted, but only if you're not connected to the debugger.
Prior to this discovery, had
va_end()
ever been used?
-
@dkf said in alloca() is hard...:
@gąska No. If you're the programmer who has a problem avoiding being an idiot, use something other than C. C is a language for non-idiots; it punishes the dumb and ill-thought-out (sometimes by letting their code work for a while before crashing in flames).
Still, removing mostly useless features is good. Given how local variables work,
alloca()
is almost entirely useless in C++, and absolutely useless in C.
-
@pjh said in alloca() is hard...:
@wharrgarbl said in alloca() is hard...:
va_start your parameter list twice and the memory is corrupted, but only if you're not connected to the debugger.
Prior to this discovery, had
va_end()
ever been used?Yes, I did research and tried a few variations on that thing. Also, unlike MSVC this thing wants a pointer to my va_list when I call vsprintf, or wtfdevice just resets.
fopen instead of snowflake_open resets the device
Unless you need to "open" stdin, then you use fopen. If you call an input function with stdin closed the keyboard doesn't work. But if you call snowflake_function with stdin open wtfdevice resets.
Its like those damn bastards created it as a puzzle.
-
@weng said in alloca() is hard...:
- SO STANDARDIZE SOMETHING SIMILAR.
- SO DEFINE IT WHEN YOU STANDARDIZE SOMETHING SIMILAR.
It's too fucking late. So much code still doesn't even use C99, much less C11 or C14, and compilers always go for the lowest common denominator by default, because the alternative is worse.
Ugh.
-
@wharrgarbl said in alloca() is hard...:
@pjh said in alloca() is hard...:
@wharrgarbl said in alloca() is hard...:
va_start your parameter list twice and the memory is corrupted, but only if you're not connected to the debugger.
Prior to this discovery, had
va_end()
ever been used?Yes, I did research and tried a few variations on that thing. Also, unlike MSVC this thing wants a pointer to my va_list when I call vsprintf, or wtfdevice just resets.
fopen instead of snowflake_open resets the device
Unless you need to "open" stdin, then you use fopen. If you call an input function with stdin closed the keyboard doesn't work. But if you call snowflake_function with stdin open wtfdevice resets.
Its like those damn bastards created it as a puzzle.
va_list
is... interesting. I've seen it act as pass-by-value, pass-by-reference, or a mix depending on compiler/platform. And (at least based on the man page)va_start()
andva_end()
must always be paired on the same brace level or it may not even compile - it is explicitly allowed forva_start()
to begin a nested block whichva_end()
closes.It boggles me that the varargs mechanism which was used before that was apparently even worse.
-
@heterodox as far as I'm aware, C11 is the most recent standard. I've not heard of C14.
-
@pleegwat at least on Windows, if you look in the headers it's just macros that do simple pointer arithmetic. I shudder to think what other platforms might require that isn't that...
-
@dkf said in alloca() is hard...:
@gąska No. If you're the programmer who has a problem avoiding being an idiot, use something other than C. C is a language for non-idiots; it punishes the dumb and ill-thought-out (sometimes by letting their code work for a while before crashing in flames).
This. One of our devs was generating bitmaps in memory. Was working fine in dev builds, but when we tried it on release it was making corrupted pictures. NFC what the underlying problem was, but I think it involved the alpha channel cute bytes.
-
@lb_ said in alloca() is hard...:
@heterodox as far as I'm aware, C11 is the most recent standard. I've not heard of C14.
It's commonly used in radiocarbon dating.
-
@tsaukpaetra said in alloca() is hard...:
alpha channel cute bytes
-
@pleegwat said in alloca() is hard...:
I've seen it act as pass-by-value, pass-by-reference, or a mix depending on compiler/platform.
Also called pass-by-wtf…
-
@tsaukpaetra said in alloca() is hard...:
NFC what the underlying problem was
Could be a compiler bug. Those are thankfully rare animals, but when you encounter one you always end up thinking “ just happened?!”
-
@dreikin said in alloca() is hard...:
@tsaukpaetra said in alloca() is hard...:
alpha channel cute bytes
I have no idea where "cute" came from....
-
@dkf said in alloca() is hard...:
@tsaukpaetra said in alloca() is hard...:
NFC what the underlying problem was
Could be a compiler bug. Those are thankfully rare animals, but when you encounter one you always end up thinking “ just happened?!”
Yeah, the dev in question did say the actual code was wrong, but somehow it was actually working fine without the optimizations enabled.
-
@tsaukpaetra said in alloca() is hard...:
@dreikin said in alloca() is hard...:
@tsaukpaetra said in alloca() is hard...:
alpha channel cute bytes
I have no idea where "cute" came from....
Perhaps you've got an infection? It looks like it's acute.
-
@dkf said in alloca() is hard...:
Could be a compiler bug. T
Is the code below wrong or I found one of these?
somefunction(functionthatreturnastruct().somechararray);
Program was crashing here until I changed it to use a temp variable
-
@wharrgarbl said in alloca() is hard...:
@dkf said in alloca() is hard...:
Could be a compiler bug. T
Is the code below wrong or I found one of these?
somefunction(functionthatreturnastruct().somechararray);
Program was crashing here until I changed it to use a temp variable
E_INSUFFICIENT_INFORMATION
Although if the only change you made was to turn it into
char temp[] = functionthatreturnastruct().somechararray; somefunction(temp);
then I think that should've worked.
Simple demo here:
https://ideone.com/YtBby0#include <stdio.h> #include <stdbool.h> struct MinMaxStruct { bool isSet; char values[2]; }; int getHead(char values[]) { return values[0]; } struct MinMaxStruct getMinMax() { struct MinMaxStruct mms; mms.values[0] = '0'; mms.values[1] = '9'; mms.isSet = true; return mms; } int main(void) { char min = getHead(getMinMax().values); printf("%c", min); return 0; }
-
@wharrgarbl said in alloca() is hard...:
Is the code below wrong or I found one of these?
Returning of values larger than will fit in a register (i.e., larger than a
void*
, or larger than adouble
if you're returning a floating point number) is deeply horrible in C, depending on mysterious copies and possibly either global or per-thread temporary areas. Don't do it (especially with any function that you're not forcing to beinline
). Much better to get the caller to allocate the space (e.g., on the stack), pass a pointer to that in, and have the called function write into that; it's effectively how you do out-parameters in C. It's not pretty, but it is reliable.Small structs (i.e., things that will pack into a register) can be safely returned, but they tend to be unusual data structures in real programs (and the bit-stuffing required to work with them gets tedious and irritatingly expensive in inner loops too).
-
@gąska said in alloca() is hard...:
Given how local variables work, alloca() is almost entirely useless in C++, and absolutely useless in C.
I'm curious about the word "almost" here. I can't think of any use for this function.
-
@dkf said in alloca() is hard...:
@wharrgarbl said in alloca() is hard...:
Is the code below wrong or I found one of these?
Returning of values larger than will fit in a register (i.e., larger than a
void*
, or larger than adouble
if you're returning a floating point number) is deeply horrible in C, depending on mysterious copies and possibly either global or per-thread temporary areas. Don't do it (especially with any function that you're not forcing to beinline
). Much better to get the caller to allocate the space (e.g., on the stack), pass a pointer to that in, and have the called function write into that; it's effectively how you do out-parameters in C. It's not pretty, but it is reliable.Small structs (i.e., things that will pack into a register) can be safely returned, but they tend to be unusual data structures in real programs (and the bit-stuffing required to work with them gets tedious and irritatingly expensive in inner loops too).
In the example given, isn't that irrelevant? It should just be reordered by the compiler into something equivalent to the temp variable version anyway, right?
-
@dreikin said in alloca() is hard...:
should
You use that word. You should know better. ;)
C is low level. The compiler doesn't do advanced transformations like outright altering the signature of functions.
-
@dkf said in alloca() is hard...:
@dreikin said in alloca() is hard...:
should
You use that word. You should know better. ;)
C is low level. The compiler doesn't do advanced transformations like outright altering the signature of functions.
Perhaps I should, but in this case my (limited) understanding of C is that the result of the original call
somefunction(functionthatreturnastruct().somechararray);
is the same as:
- call
functionthatreturnastruct()
- acquire a reference to the
somechararray
member of the result from the previous, which being an array is a pointer - pass that pointer into
somefunction
Wait, no, I see the problem you're talking about now. It's not between 2 & 3, it's between 1 & 2, isn't it?
- call
-
@wharrgarbl said in alloca() is hard...:
@dkf said in alloca() is hard...:
Could be a compiler bug. T
Is the code below wrong or I found one of these?
somefunction(functionthatreturnastruct().somechararray);
Program was crashing here until I changed it to use a temp variable
I had a piece of code in C# that was like this, the only thing the function did was call the real function using an awaiter thing.
Grabbing the awaiter return thing into a variable and then returning that worked, whereas directly returning it basically caused the awaiter to never run at all.
-
@dkf Everything I found said the convention for large return values is the caller to allocate it (in the stack I suppose) and pass a pointer.
-
@wharrgarbl It's an issue of scope.
If you assign the return value to a temp variable, that temp variable has scope until the end of its block. Without a temp, the return value goes out of scope and can be deallocated before the call into somefunction.
-
@mzh said in alloca() is hard...:
@gąska said in alloca() is hard...:
Given how local variables work, alloca() is almost entirely useless in C++, and absolutely useless in C.
I'm curious about the word "almost" here. I can't think of any use for this function.
Variable-length array on stack. In standard C++ it's pretty much impossible, so alloca() is kinda-sorta necessary if you really really don't want ridiculously big fixed-size buffer and/or risk out of bounds access/incomplete data, and you're afraid of heap. C99 has a different, better feature that can be used for variable-length arrays, called variable-length arrays. It's very simple - just declare your array with variable length.