alloca

K

Keith Thompson

CBFalconer said:
No, code you can write down, that is portable, is topical here.
However you can't do that for alloca. For example, you can code
'between' to decide if a <= b <= c, by:

int between(int a, int b, int c) {
if ((a <= b) && (b <= c)) return 1;
return 0;
}

Why so verbose?

int between(int a, int b, int c) {
return a <= b && b <= c;
}
 
Y

ymuntyan

Mmmm, but still


??

That is, even though microsoft calls the function _alloca
the microsoft user would still call alloca (no underscore)?
If that is not the case, if the user has to call (e.g.,) _alloca
then your "The syntax is" is not accurate. But that would
appear to contradict your assertions of how widespread and
portable it is.

Sorry but my head is starting to hurt, trying to come up with
ways that you could -somehow- be correct -and- not have
contradicted yourself...

Yes, if you are using MS libraries, your head may hurt. And no,
no contradiction here. It's a feature, which makes conforming
compiler mode actually work (as opposed to e.g. effect of
gcc's -std=whatever flag) when you ask for it.

Yevgen
 
R

Richard Heathfield

Eric Sosman said:
Andrey Tarasevich wrote:


Exactly: C has a portable and safer (though still not
entirely safe) feature that offers all the advertised benefits
of alloca(). Why reject it in favor of something that is
less portable and more dangerous?

Typical alloca implementations return NULL on failure, as an advertised
benefit. VLAs don't do this. If an attempt to define a VLA fails, the
behaviour is undefined, which is no good to anybody. In that sense, alloca
is a vast improvement.

VLAs are a *non*-portable and badly flawed attempt to fill an effectively
non-existent gap.
 
E

Eric Sosman

Richard said:
Eric Sosman said:


Typical alloca implementations return NULL on failure, as an advertised
benefit. VLAs don't do this. If an attempt to define a VLA fails, the
behaviour is undefined, which is no good to anybody. In that sense, alloca
is a vast improvement.

Jacob's advertisement for alloca() said
> o There is the risk of stack overflow if you allocate too much memory
> with it. If it fails it returns NULL, but do not count on it.

.... and there's also Gordon Burditt's experience
> - In all the implementations I have seen, it does NOT make any attempt
> to detect stack overflow and return NULL on error. This is a
> serious problem, the gets() of memory allocation.

.... so I'm not sure how "typical" the implementations you refer
to might be.
VLAs are a *non*-portable and badly flawed attempt to fill an effectively
non-existent gap.

VLA's are a *fully* portable and badly flawed attempt, etc.
I've written C for more than three decades without ever needing
or even wanting to use either VLA's or alloca(). Maybe my brain
isn't twisty enough.
 
M

Morris Dovey

Andrey said:
Huh? I think it is pretty clear from my quote above that it's 'alloca' that is
rejected and I'm in no way opposed to that rejection. I never even thought about
rejecting VLAs. Where are you getting this from?

When allocation of a VLA fails, how does the program know and
what recovery is possible?

Abort, retry, fail?
BSoD?
 
R

Richard Heathfield

Eric Sosman said:
Jacob's advertisement for alloca() said


... and there's also Gordon Burditt's experience


... so I'm not sure how "typical" the implementations you refer
to might be.

That's a fair comment, I guess - although my own comment was made after I'd
checked the documentation for a number of implementations I have here and
found that (with only one exception) they return NULL if the space can't
be allocated. The exception throws an exception. :)
VLA's are a *fully* portable and badly flawed attempt, etc.
I've written C for more than three decades without ever needing
or even wanting to use either VLA's or alloca(). Maybe my brain
isn't twisty enough.

If you mean they're fully portable because by virtue of not using them at
all, you get equal use out of them on any platform, I can concur.
Otherwise, no. Even on implementations where VLAs are implemented (which
is by no means all), they are not always implemented in a C99-conforming
manner. The gcc implementation is a classic example.
 
K

Keith Thompson

Andrey Tarasevich said:
Memory allocated by 'alloca' function obeys rather artificial
non-C-ish lifetime rules, which might easily lead to rather nasty
surprises when used without caution (did anyone mention
newcomers?). In C99 language VLAs provide support for run-time sized
automatic memory, essentially eliminating the need for 'alloca'.

And *if* alloca were to be standardized, the standard would have to
specify its behavior in considerably more rigorous detail than has
ever been done by any of the existing implementations of it. The
behavior wouldn't necessarily have to be well defined in all cases,
but the standard would at least have to specify precisely the cases in
which the behavior is undefined. The behavior when alloca() is called
as part of a function argument would probably be left undefined, but
what about other corner cases?

Just one example off the top of my head:

{
int n = rand() % 1000 + 1;
int *p;
int vla[(p = alloca(n), n)];
}

Obviously that's a silly thing to do, but the standard would need
either to define its behavior or to make it clear that it's undefined.
It might be easier to define the cases where the behavior *is*
defined, perhaps something similar to the tight restrictions on
setjmp() and longjmp().

And if the standard were to define the behavior in cases that don't
work properly in all existing implementations, then existing
implementations would be non-conforming, and code that depends on the
new standard's semantics would be *quietly* non-portable to older
implementations.

Furthermore, the idea of an allocation function that can't signal an
out-of-memory condition is disturbing. (I wish VLAs had a way to do
this.)

alloca was IMHO a nice idea, but it's turned out to be largely
impractical in real life.

I note, however, that jacob hasn't actually advocated that alloca
should be standardized, merely that it should be used. He's
indirectly performed a public service, by giving us an opportunity to
warn newbies away from it.
 
A

Andrey Tarasevich

Eric said:
It's not obvious to me, but I've used fewer than fifty
C implementations and my experience may not be as broad as
yours. How many implementations did you study before
reaching your conclusion?

I don't exactly understand why you seem to assume that my conclusion is supposed
to be based specifically on "studying implementations". I already explained that
my conclusion is based solely on the fact of the existence of VLAs. I already
commented the differences between VLAs and 'alloca'. Exhaustively, in my opinion.
Exactly: C has a portable and safer (though still not
entirely safe) feature that offers all the advertised benefits
of alloca(). Why reject it in favor of something that is
less portable and more dangerous?

Huh? I think it is pretty clear from my quote above that it's 'alloca' that is
rejected and I'm in no way opposed to that rejection. I never even thought about
rejecting VLAs. Where are you getting this from?
 
K

Keith Thompson

Andrey Tarasevich said:
Yes, trivial, in a sense that there's no actual requirement for a
solution you seem to imply. The implementation can simply _ignore_ the
problem by stating that using the function in certian contexts is not
allowed, i.e. it's UB.
[...]

Yes, implementations can and do do exactly that. What they don't do,
from what I've seen, is define rigorously which uses of alloca() are
well defined and which are undefined. If you do anything non-trivial
with it, you run the very real risk of running into one of the
undocumented cases where it doesn't work.

That's why most systems that implement alloca() provide documentation
that warns strongly against using it.
 
K

Keith Thompson

Andrey Tarasevich said:
Keith said:
No, a compiler that provides alloca() *doesn't* have to make sure that
the argument passing mechanism works correctly. Since no standard
defines the behavior of alloca(), a compiler is free to leave its
behavior undefined in any circumstances where making it work would be
inconvenient.
...

That's just another way to circumvent the potential problem with using
alloca' in an argument list. Just say that behavior is undefined in
this case. A quality implementation might perform a run-time stack
integrity check in debug configuration and trigger a run-time
diagnostic.

Although I don't direct connection to the 'alloca' being standard or
not. There are perfectly _standard_ features that produce undefined
behavior in circumstances "where making it work would be
inconvenient". Like, for example, the range of 'ptrdiff_t' is not
required to be sufficient for any [otherwise legal] pointer
subtraction operation, and trying to subtract pointers which are too
far apart produces UB.

Right. The difference is that the standard defines precisely when the
behavior is defined and when it isn't, and precisely what the behavior
is when it's defined. (At least it valiantly attempts to do so; no
human-created artifact is perfect.) alloca(), as it currently exists,
is undefined in circumstances that are poorly specified.

It would almost certainly be *possible* to standardize alloca(). It
just wouldn't have been worth the effort. And because alloca() is
non-standard, it's been left in this ill-defined state that makes it
dangerous to use, as well as being non-portable.
 
C

Chris Torek

No-one in their right mind would do that :) Incidentally, does the
standard prohibit doing it with setjmp()?

Yes: the Standard says that setjmp is a macro, not a function.
Incidentally, this makes a number of implementations non-conforming
simply because they happen to use a function instead of a macro.
(A conforming program can discover this via #ifndef:

#include <setjmp.h>

#ifndef setjmp
# error "setjmp is not a macro"
#endif

The cure for this is to define a macro that calls the function:

#define setjmp setjmp

in <setjmp.h> will suffice.)

The "does not work through function pointer" problem (for alloca())
can thus be overcome in a future standard in the same way that it
was for setjmp(). (This does not mean I think a future standard
*should* attempt to standardize alloca(), nor that I think it should
not. There are tradeoffs here and I have not attempted to study
them sufficiently.)
 
R

Richard Tobin

Richard Heathfield said:
Typical alloca implementations return NULL on failure

I think it's rather difficult to do that on many systems, and this is
equally true for any other stack-allocated memory. Unix systems for
example extend the stack as required up to a settable limit; to find
out whether the allocation will succeed you have to either (a)
determine the limit (which may change, so you need to check it each
time), or (b) try accessing the memory, which will result in a
segmentation fault if it fails, which the user may already be
catching.

-- Richard
 
R

Richard Tobin

No-one in their right mind would do that :) Incidentally, does the
standard prohibit doing it with setjmp()?
[/QUOTE]
Yes: the Standard says that setjmp is a macro, not a function.

That doesn't quite answer the question. For example, if we have
#define setjmp setjmp

then it will still "work" to assign it to a function pointer. Is the
assignment undefined behaviour?

-- Richard
 
C

Chris Torek

[Richard Tobin, I think, asked:]
... does the standard prohibit [taking the address of] setjmp()?

Yes: the Standard says that setjmp is a macro, not a function.

That doesn't quite answer the question. For example, if we have


then it will still "work" to assign it to a function pointer. Is the
assignment undefined behaviour?

Although it will "work" in terms of not producing an immediate
error, it is indeed undefined behavior. The Standard never says
anything one way or the other about computing addresses of macros
in general, so, by specifying that setjmp is a "macro", and failing
to say anything about taking the address of whatever that macro
expands to, the Standard effectively forbids the programmer from
taking the address, without requiring implementors to make their
implementation produce a diagnostic.
 
C

CBFalconer

Richard said:
.... snip ...

I sense a disturbance in the Force - and not an unwelcome one, from
my perspective. Nevertheless, you are expressing a minority view.

Amusing. Time after time I see a response to something by someone,
followed (in varying orders) by responses from Twink, Richard,
McCormack, all caught by my troll filter. Sometimes they go around
again.
 
C

CBFalconer

Chris said:
[Richard Tobin, I think, asked:]
That doesn't quite answer the question. For example, if we have

#define setjmp setjmp

then it will still "work" to assign it to a function pointer.
Is the assignment undefined behaviour?

Although it will "work" in terms of not producing an immediate
error, it is indeed undefined behavior. The Standard never says
anything one way or the other about computing addresses of macros
in general, so, by specifying that setjmp is a "macro", and
failing to say anything about taking the address of whatever that
macro expands to, the Standard effectively forbids the programmer
from taking the address, without requiring implementors to make
their implementation produce a diagnostic.

But, I believe, the standard says that a macro expansion will not
recurse, so that the expansion will leave the word 'setjmp'. Now,
in a later phase, that tries to call something.
 
G

Gordon Burditt

VLAs have a fatal flaw. What happens if there is not enough auto
memory for the allocation?

alloca() could overcome that by returning NULL in that instance.

Do you know of any implementation of alloca() that actually DOES that?
I don't believe gcc does.
 
U

user923005

Do you know of any implementation of alloca() that actually DOES that?
I don't believe gcc does.

No, but I made my own version that does (it relies on non-portable
stuff).

C:\tmp>cl /D__STDC__ /DUNIT_TEST alloca.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762
for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

alloca.c
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation. All rights reserved.

/out:alloca.exe
alloca.obj

C:\tmp>alloca
alloca(100) succeeded!
alloca(1000000000) failed.

C:\tmp>type alloca.c

/*
OK, so it's not really C.
But this shows that an implementation specific compiler can 'do the
right thing'.
IMO-YMMV
*/
#include <windows.h>
#include <malloc.h>
#include <excpt.h>

void *alloca(size_t size)
{
void *p;
__try
{
p = _alloca(size);
}
__except(GetExceptionCode() == STATUS_STACK_OVERFLOW) {
int result = _resetstkoflw();
return NULL;
}
return p;
}

#ifdef UNIT_TEST
#include <stdio.h>
int main(void)
{
size_t size = 100;
char *p = alloca(size);
if (p == NULL)
printf("alloca(%u) failed.\n", (unsigned) size);
else
printf("alloca(%u) succeeded!\n", size);
size = 1000000000;
p = alloca(size);
if (p == NULL)
printf("alloca(%u) failed.\n", (unsigned) size);
else
printf("alloca(%u) succeeded!\n", size);
return 0;
}
#endif
 
G

Gordon Burditt

VLAs have a fatal flaw. =A0What happens if there is not enough auto
Oh, yes, I should have also asked for an implementation that actually
DOCUMENTS that alloca() returns NULL on failure, regardless of what
the code does.
No, but I made my own version that does (it relies on non-portable
stuff).

Ok, alloca() usually relies on unportable stuff and hooks into the compiler.
C:\tmp>cl /D__STDC__ /DUNIT_TEST alloca.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762
for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

alloca.c
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation. All rights reserved.

/out:alloca.exe
alloca.obj

C:\tmp>alloca
alloca(100) succeeded!
alloca(1000000000) failed.

C:\tmp>type alloca.c

/*
OK, so it's not really C.
But this shows that an implementation specific compiler can 'do the
right thing'.
IMO-YMMV
*/
#include <windows.h>
#include <malloc.h>
#include <excpt.h>

void *alloca(size_t size)
{
void *p;
__try
{
p =3D _alloca(size);
}
__except(GetExceptionCode() =3D=3D STATUS_STACK_OVERFLOW) {
int result =3D _resetstkoflw();
return NULL;
}
return p;
}

Um, HOLD IT! Doesn't, by definition, the storage allocated by
_alloca(), which I presume is Microsoft's implementation of alloca(),
get freed when the function calling _alloca() returns? Doesn't
that mean that your alloca() returns a pointer to already-freed
storage? That won't work very well. alloca() doesn't like wrappers.

Also, are you guaranteed to get an exception if you overflow the
stack? Ok, if you overflow it by a meg or less, probably. If you
overflow it by the address difference between the current stack
pointer and &main, (say, a few gigabytes) maybe not. You have
demonstrated a halfway reasonable way of stack checking that probably
works most of the time.
 
D

Dik T. Winter

> jacob navia wrote: ....
>
> That's odd: The Rationale says "Such a function is not
> efficiently implementable in a variety of environments, so
> it was not adopted in the Standard." What do you know that
> the couple hundred contributors to the Standard didn't?

Moreover, there are systems where it is *not* implementable as such and
would be just an alias for malloc (now, who cares about a memory leak).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top