0

If I try to run this code and give for example "Hello" (more than 3 chars) as an input for scanf, the array str doesn't overflow. This sounds a little bit strange to me, but of course I'm missing something. Does anyone know what's the problem here? Thanks a lot!

char str[3];
scanf("%s", str);
printf("%s\n", str);
J-Alex
  • 6,881
  • 10
  • 46
  • 64
L. Carbini
  • 55
  • 1
  • 5
  • 2
    Overwriting the bounds of your array is [undefined behavior](https://stackoverflow.com/documentation/c/364/undefined-behavior/2144/accessing-memory-beyond-allocated-chunk). If by "doesn't overflow" you mean "prints out without seg-faulting",, you just got lucky this time. "Hello" can't fit in `str`, so you are overflowing it. Or really _unlucky_,, since you will think everything is fine and then your program will crash when you least expect it. – yano Jul 28 '17 at 23:19
  • 1
    Not really related, but just to note that inputting more than 2 chars would invoke ub. There are a few of runtime tools you can use to catch this kind of error and warning flags won't catch this but are still useful for catching other ub invoking code, such as attempting to read uninitialised variables. – George Jul 28 '17 at 23:26
  • That's actually really strange because I'm trying to input every string that comes to my mind and no error is shown. Maybe it's just a "modern" compiler that handles all of that automatically. I'm just compiling it using the Terminal on Mac and typing "gcc -o fs main.c" and then running it there. – L. Carbini Jul 28 '17 at 23:42
  • In the case I would need an array of variable length because the length of my input is unknown, the only way to add memory to it, should be realloc(), right? Are there other ways to bypass this problem? – L. Carbini Jul 28 '17 at 23:48
  • 1
    Use 'char str[4096];' and 'sscanf("%4096s",str);'. That should be big enough? – Martin James Jul 29 '17 at 00:11
  • 1
    Undefined behavior can manifest in any way, including appearing to work as expected; but don't rely on this behavior. Changing or adding a line of code to the program could be enough to trigger some other behavior. For input of unknown size, you might use an input buffer large enough to handle all expected input. A VLA could then be declared to suit the input; or you can dynamically allocate space with `malloc()` et al. You can't resize an array or a variable length array once they are declared, though, even with `realloc()`. – ad absurdum Jul 29 '17 at 00:13
  • 2
    @MartinJames-- that should be `scanf("%4095s", str);` to leave room for the null terminator. To use `sscanf()` you need to add another argument for the input string. – ad absurdum Jul 29 '17 at 00:16
  • 1
    If you are reading more than 3 characters into an array of three, you are "overflowing" (i.e. accessing elements beyond the end of the array). The behaviour of such a thing is undefined. It can, but is not required to, give you a visible symptom (such as a runtime error). Lack of symptom doesn't mean the behaviour is correct. – Peter Jul 29 '17 at 00:35
  • 3
    Possible duplicate of [Why doesn't scanf() generate memory clobbering errors when filling array.](https://stackoverflow.com/questions/31764317/why-doesnt-scanf-generate-memory-clobbering-errors-when-filling-array) – Bo Persson Jul 29 '17 at 11:40
  • @DavidBowling thanks - you are, of course, correct :) – Martin James Jul 29 '17 at 12:54

3 Answers3

2

You said, "the array str doesn't overflow", but how do you know? How did you expect the overflow to manifest itself?

In fact, the array did overflow. You just got "lucky", and there were no (visible) repercussions.

One of the tricky things to understand about computer programming is that enforcement of the rules can be pretty inconsistent. (Computer programming is not unlike life in this regard.) If the signal at the intersection says "Don't Walk", but no cars are coming so you cross the street anyway, how surprised are you if no policeman instantly appears and writes you a ticket for jaywalking? That's basically what happened here.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
1

I tried to run your code, and it does segfault:

./main 
ofejnhofewnhouwnofwbeqofenoifwenofwenoubwuiowgebouwegfougewfnbnbboue
ofejnhofewnhouwnofwbeqofenoifwenofwenoubwuiowgebouwegfougewfnbnbboue
Segmentation fault (core dumped)

I don't know how many characters you are trying to pass in scanf() but you have to know that sometimes the compiler performs a padding between saved ESP/EIP and the initial variable.

Especially, here, you are creating a memory area of 3 bytes on the stack, the compiler will first round it to 4 (or 8 on x64?). But even then, it might add more space.

In gdb, a disass main gives me:

   0x000000000040057d <+0>: push   %rbp
   0x000000000040057e <+1>: mov    %rsp,%rbp
   0x0000000000400581 <+4>: sub    $0x20,%rsp

sub 0x20 is 32 bytes, obviously way more than 3 bytes.

Do not expect a strict "dummy" C to assembler directives, nowadays the compilers perform a lot of optimizations and decisions than you might be aware of.

Trying to find the exact range of bytes between your buffer and EIP usually requires to perform a brute-force, but a clever hacker might find more interesting approaches... ;-)

Fabien
  • 4,862
  • 2
  • 19
  • 33
1

C runtime does not issue an error/warning message but produces incorrect result. To check the Overflow/Underflow is your responsibility.

Rahul
  • 130
  • 2