arrayscpointersstackmemory-corruption

Weird array length behaviour in C (memory corruption?)


I'm fully aware that, when passed to a function, an array just decays to a pointer, so you can't use sizeof(x)/sizeof((x)[0]) to work out their size. However, I found out that one can use (&x)[1]-x, i.e. pointer arithmetic, so, out of curiosity, I tried to make a function that takes two arrays, works out their lengths, and joins them (using malloc to dynamically allocate a chunk of memory whose size is the sum of their lengths, times the size of an int).

This works:

#define ARR_LEN(a) ((&(a))[1]-(a))

void join (int a[], int b[]) {
  printf("%zu %zu", ARR_LEN(a), ARR_LEN(b));
}

int main() {
    int a[3] = {0, 1, 2};
    int b[5] = {0, 1, 2, 3, 4};
    
    join(a, b);

    return 0;
}

It prints 3 5. However, changing the body of join to store ARR_LEN(a) in a local variable n, even after we print ARR_LEN(a) the first time:

int n;
    
printf("%zu %zu", ARR_LEN(a), ARR_LEN(b));
n = ARR_LEN(a);

causes seemingly pseudorandom results such as 18446708891292021383 5. Weirdest of all, it works fine, printing 3 5, when n is global, rather than local. Additionally, then printing the contents of n gives a different number to the first.

My guess is that, when a and b are on the stack, putting n on there somehow causes the C compiler to get confused about their sizes, although this issue persists when I declare n as int __attribute__ ((aligned (256))) to try to force it away from the other two (and any weird caching problems). When I print &a, &b and &n, I get something like:

0x7ffd680a8df8 0x7ffd680a8df0 0x7ffd680a8e00

While, when n is global, &n is 0x404200, since .data is below the stack. Additionally, when n is global and I instead, say, put a local variable m = ARR_LEN(b), a gets "corrupted" while ARR_LEN(b) is again correctly printed.


Solution

  • This works:

    No, it does not. You were lucky. As function parameters int a[] and int *a mean exactly the same.

    There is no way to take the size of the passed array, and no "hacky tricks" exist.