tags:

views:

384

answers:

3

I have been playing around with the stack on a Ubuntu 9.04 system running gcc 4.3.3 with the randomize_va_space kernel variable set to 0(/proc/sys/kernel/randomize_va_space)

If I declare an auto variable in a function which is an array with its size being determined by the input then how is the array allocated on the stack?

The function looks something like this -

int fun(int i) {
    char a[i];
    char *ptr;

    printf("a - %p ptr - %p\n", a, &ptr);
    printf("Difference - %ld\n", ((unsigned long)&ptr - (unsigned long)a);
    printf("sizeof(a) - %d\n\n", sizeof(a));
}

The sizeof operator when passed the array a returns the expected size (even -1)so I was wondering why does the array take so much space on the stack, and secondly why is sizeof() returning a -1?

The output looks something like this -

a - 0xbffff4c0 ptr - 0xbffff4fc
Difference - 60
sizeof(a) - -1

a - 0xbffff4c0 ptr - 0xbffff4fc
Difference - 60
sizeof(a) - 0

a - 0xbffff4c0 ptr - 0xbffff4fc
Difference - 60
sizeof(a) - 1

a - 0xbffff4b0 ptr - 0xbffff4fc
Difference - 76
sizeof(a) - 2

a - 0xbffff4b0 ptr - 0xbffff4fc
Difference - 76
sizeof(a) - 3

a - 0xbffff4b0 ptr - 0xbffff4fc
Difference - 76
sizeof(a) - 4
A: 

I'm surprised this compiles. The compiler cannot allocate memory on the stack at compile time unless it know how much to allocate. When you allocate using 'new' or 'malloc', the memory is allocated off the heap. Here's what I get when I compile this:

alloc.c(2) : error C2057: expected constant expression
alloc.c(2) : error C2466: cannot allocate an array of constant size 0
alloc.c(2) : error C2133: 'a' : unknown size
alloc.c(7) : warning C4034: sizeof returns 0

I think the rest of the question is moot.

Ashwin
Compilers certainly can allocate memory on the stack with a size determined at runtime - that's what alloca() does on compilers that support it.
Michael Burr
+1  A: 

A compiler that supports C99 variable array semantics should compile this (though I don't really have much experience with var arrays).

What is the value of i being passed in for each of those iterations? That would help explain why aizeof() is returning -1 in some cases.

According to this page:

variable length arrays are working in mainline GCC, but according to:

they were broken in GCC 4.3. That probably explains the issues you're seeing with sizeof().

Michael Burr
The value returned from sizeof() is the value that was passed into the function as 'i'.
muteW
The C99 standard says that each time the expression in the array declaration is evaluate it shall have a value greater than 0. When you pass in -1 or 0 you'll get undefined behavior - in this case you get a sizeof() == -1 or 0. As for why the array seems to take so much space even for small values of i - I don't know (remember, the GCC C99 status docs say that the support was broken).
Michael Burr
+3  A: 

Variable-length automatic arrays were introduced to C in C99.

The array is allocated by adjusting the stack pointer by the array size, just like a normal automatic variable - the only difference is that the size of the stack pointer adjustment and the offset of a from the frame pointer are not constants that can be calculated at compile-time - they must be calculated at runtime.

Similarly, for sizeof to work correctly on variable-length arrays, when it's applied to such an array it can't be calculated at compile-time either. The allocated size of a must be remembered when the scope is entered.

It's this housekeeping information - the number, size and offset of variable-length automatic arrays - that is kept on the stack in the extra space you're seeing between a and ptr. There might be an additional saved frame pointer there too - you'd really have to dig into the source for your compiler to find out.

Oh, and the reason you're seeing -1 from sizeof is because you're printing it incorrectly with the %d specifier - use %zu for size_t.

caf