2

I have the program below. If i declare variables a,b,c static global variables, it gives segmentation fault, but if i declare them non-static global or as local variables, it won't give segmentation fault. Why does it behave in such a way? I know that there is more data than variables can store, but why does it give seg fault when only its declared static? Are statically declared variables stored in some different part of the the stack frame where overwriting is not allowed?

EDIT: I know strcpy is not safe. But that is not my problem. I want to understand why one overflow gives segfault, why the other overflow might not give segfault.

#include<stdio.h>
#include<string.h>

static char a[16];
static char b[16];
static char c[32];

int main(int argc, char *argv[]){

// char a[16];
 //char b[16];
 //char c[32];
    strcpy(a,"0123456789abcdef");
    strcpy(b,"0123456789abcdef");
    strcpy(c,a);
    strcpy(c,b);
    printf("a = %s\n",a);
    return 0;
}
Neo
  • 349
  • 5
  • 18
  • When you write beyond the end of a buffer, you are writing into arbitrary memory, which can have undefined behavior. – merlin2011 Apr 07 '15 at 21:40
  • 1
    This is what is called undefined behavior. Don't ask about something that is undefined. – Eugene Sh. Apr 07 '15 at 21:40
  • It's odd that you only get the crash if they're static, since the difference between static and non-static global variables should only be a matter of scope. (Of course, this *is* allowed behaviour according to the C language, which says anything can happen) – user253751 Apr 07 '15 at 21:51
  • I would suspect that your compiler does allocate static globals in a different way to non-static globals, so there happens to be a 0 byte not long after the end of c, but there isn't when they aren't static. – user253751 Apr 07 '15 at 21:52
  • accessing memory beyond the end of a buffer is undefined behaviour. Since it is undefined behaviour, anything can happen. anything. so, sometimes the behaviour is a seg fault event. sometimes it is something hidden that corrupts other data like the stack call chain. sometimes it is something benign. Never expect a certain behaviour. Such undefined behaviour is to be avoided at all times. The cost can be massive when some data is corrupted and a user will be very unhappy if an application ends in a seg fault event. – user3629249 Apr 08 '15 at 01:41

2 Answers2

1

Careful that const char* string in C are always 0-terminated, meaning that the string "0123456789abcdef" is actually 17 characters: "0123456789abcdef\0"

I suggest you to use always the secure version

strncpy() 

You can also have a look at the documentation which tells you explicitly that the null character is included.

http://www.cplusplus.com/reference/cstring/strcpy/

slux83
  • 686
  • 9
  • 20
  • 2
    `strncpy` is not secure and it would not help in this case. There's very few situations where `strncpy` is the right function to use – M.M Apr 07 '15 at 21:47
  • @slux83 thanks for that. I know it, but my question is why doesn't it give a segfault when its not static. – Neo Apr 07 '15 at 21:50
  • It doesn't give you a undefined behavior. It might segfault as well if your program wouldn't be that short. The problem of stack corruption is that the time that you discover the crash is unpredictable. – slux83 Apr 08 '15 at 06:40
  • @Matt using the strncpy is always a good practice because you limit the copy specifying the size of your buffer, in case you miss the null character for some obscure reason – slux83 Apr 08 '15 at 06:42
  • @slux83 no, it's a bad practice . Using `strncpy` in this case would still cause a buffer overrun (although of different sort) because strncpy does not null-terminate the string when it doesn't fit. – M.M Apr 08 '15 at 12:15
0

memory alignment matters in stack variable. Try it with -fstack-protector-strong or similar stack protection option you will see the crash. Also declare an int after c and overflow your array c, you can see the crash. you need to make sure that there is no padding. since b is an array, whatever you overflow from 'a' goes to b. Try something like:

struct foo {
        char c[10];
        int x;
    } __attribute__((packed));

you will see the crash when you overflow c.

You are hitting undefined behaviour when you overflow.

resultsway
  • 12,299
  • 7
  • 36
  • 43