1

So I have this code:

#include <stdio.h>
int main()
{
printf("enter character\n>>>");
char input[0];


scanf("%5s",input);
printf("%s",input);
}

that excepts 5 chars from the user. I am new to C and this one thing makes no sense to me. Why does gcc allow me to compile a program that assigns values to an array with a length of 0? Surely this is not possible? Please explain.

  • First of all, an array with length 0 is not allowed in standard C. Second, in C you have to check ranges yourself. Don't rely on the compiler to warn you. (In some cases it does, but don't rely on it). Third "that excepts 5 chars" is wrong. If you want (up to) 5 characters, you must use `"%5s" in your format string. Otherwise it takes whatever you provide as input. – Gerhardh Sep 18 '22 at 20:55
  • 1
    Does this answer your question? [How dangerous is it to access an array out of bounds?](https://stackoverflow.com/questions/15646973/how-dangerous-is-it-to-access-an-array-out-of-bounds) – Gerhardh Sep 18 '22 at 20:55
  • C places a lot of responsibility on you to know what you are doing and do the right thing. There are a lot of wrong things that you can do that the compiler won't detect. – Avi Berger Sep 18 '22 at 20:57
  • @Gerhardh: I do not think that your proposed duplicate is appropriate, because that question asks about the possible security implications that go beyond the program simply misbehaving a bit. However, that is not the issue in the question at hand. – Andreas Wenzel Sep 18 '22 at 21:19
  • [What compiler options are recommended for beginners learning C?](https://software.codidact.com/posts/282565) – Lundin Sep 19 '22 at 13:16

2 Answers2

2

Your compiler ought to reject the declaration as invalid

If the expression is a constant expression, it shall have a value greater than zero. (6.7.6.2).

However, as @Joshua points out below, some compilers support this feature as an extension:

Declaring zero-length arrays is allowed in GNU C as an extension (info gcc; 6.18)

gcc -pendatic -pedantic-errors will generate an error and only warning without -pedantic-errors.

scanf() and printf() will also be undefined behavior.

Allan Wind
  • 23,068
  • 5
  • 28
  • 38
  • `gcc` allows zero length arrays as a compiler extension. That's why it's not complaining. This predates the standard `[]` for flexible array at end of structure. (Which was its only real use.) – Joshua Sep 18 '22 at 21:09
  • @Joshua Makes sense. I was kinda puzzled that -std=c17 still permit that extension. – Allan Wind Sep 18 '22 at 21:11
  • Because too many people depended on it long ago (I had other compilers that didn't forbid zero either.) – Joshua Sep 18 '22 at 21:13
  • gcc and clang with default options are non-conforming compilers. It's pretty sad since this particular feature is obsolete since 1999. – Lundin Sep 19 '22 at 13:36
1

C doesn't check for buffer overrun.

This bears repeating.

C doesn't check for buffer overrun.

This has been a source of bugs for a very long time; but also it's inherent in C and cannot be changed.

There are some simple cases where the compiler can detect buffer overrun (usually with optimizations enabled as well) but in the general case it cannot; nor will it generate any runtime checks. It will just do something unexpected. This is usually a security problem if you let it.

You must check yourself that you don't overrun buffers.

Joshua
  • 40,822
  • 8
  • 72
  • 132
  • "optimization" you probably mean "diagnostics". In GCC you don't get a warning for zero size array even with `-Wall -Wextra`. You need `-pedantic` to get some warning. – Gerhardh Sep 18 '22 at 20:57
  • @Gerhardh: Huh. I'm used to it catching statically verifiable out-of-bounds access as soon as -Wall -O1 is used. (It can't at -O0 because each statement is compiled independently.) – Joshua Sep 18 '22 at 20:58
  • Interesting... `gcc -Wall -Wextra test.c -o test` doesn't show anything. Adding `-pedantic` shows `test.c:5:6: warning: ISO C forbids zero-size array ‘input’ [-Wpedantic]`. And `-O1` only warns about not using return value of `scanf`. I never thought about optimization level affecting warnings shown. – Gerhardh Sep 18 '22 at 21:01
  • @Gerhardh: Whelp hmmm. I need some better verbage anyway. The real point is sometimes the compiler can generate out of bounds warnings but usually it just can't. – Joshua Sep 18 '22 at 21:03
  • Yes, that is true, of course. – Gerhardh Sep 18 '22 at 21:04
  • In your answer, you wrote twice: `"C doesn't check for buffer overrun."` -- This statement is not quite correct. The gcc and clang compiler does check for buffer overruns, if you compile with `-fsanitize=address`. However, in the general case, you are correct. Therefore, I am upvoting your answer. – Andreas Wenzel Sep 18 '22 at 21:27
  • @AndreasWenzel: Does not detect buffer overrun of array inside struct passed as pointer to another function. But that check is still pretty good. – Joshua Sep 18 '22 at 21:33
  • That clears up some of my questions. But if this is not aloud, why does it unfailingly work? The code compiles successfully and indeed does accept only 5 chars(when I enter 1234567, it prints 12345). And finally, why hasnt someone thought to make gcc catch this issue? – Josh Reimer Sep 19 '22 at 15:34
  • 1
    @JoshReimer: Asking why your illegal actions did not have any consequences is generally not a meaningful question. That is like asking the following: I drove my car past a traffic light that was showing red. Why was I able to reach the other end of the intersection unscathed? Why did I not collide with another car? You were probably just lucky. – Andreas Wenzel Sep 19 '22 at 15:43
  • @JoshReimer: If you invoke undefined behavior (i.e. do something illegal), what exact consequences this has depends on the internals of the compiler you are using. You cannot rely on any specific behavior. Changing the compiler will possibly change the behavior of your program. Even changing the compiler settings or updating the compiler may make change the behavior of your program. – Andreas Wenzel Sep 19 '22 at 15:53
  • @JoshReimer: The compiler generally does not perform bounds-checking run-time checks for performance reasons. Instead, it is the programmer's responsibility to make sure that you are not accessing arrays out of bounds. You can make gcc perform such run-time checks by compiling with the `-fsanitize=address` command-line option. However, this typically decreases performance by a factor of 2. Therefore, this should generally only be done for debugging purposes. – Andreas Wenzel Sep 19 '22 at 15:59