24

There is some strange code using VLA (Variable Length Arrays) which is treated as Valid C (C99, C11) by gcc 4.6:

$ cat a.c
int main(int argc,char**argv)
{
  struct args_t{
     int a;
     int params[argc];        // << Wat?
                        // VLA in the middle of some struct, between other fields
     int b;
  } args;

  args.b=0;

  for(args.a=0;args.a<argc;args.a++)
  {
    args.params[args.a]=argv[0][0];
    args.b++;
  }
  return args.b;
}

This code compiled without warnings:

$ gcc-4.6 -Wall -std=c99 a.c && echo $?
0
$ ./a.out ; echo $?
1
$ ./a.out 2; echo $?
2
$ ./a.out 2 3; echo $?
3

Same for -std=c1x:

$ gcc-4.6 -Wall -std=c1x a.c && echo $?
0

But this does not work with Intel C Compiler or with Clang+LLVM:

$ icc a.c -o a.icc
a.c(5): warning #1361: variable-length array field type will be treated as zero-length array field type
       int params[argc];
                  ^
$ ./a.icc; echo $?
47

$ clang a.c -o a.clang
a.c:5:10: error: fields must have a constant size: 'variable length array in structure' extension will never be supported
     int params[argc];
         ^
1 error generated.

So:

  1. Why is this considered valid by GCC?
  2. If it is an extension of GCC, where is it described?
  3. Is it valid in C99 and C11 ISO Standards?
Patrick Schlüter
  • 11,394
  • 1
  • 43
  • 48
osgx
  • 90,338
  • 53
  • 357
  • 513
  • 2
    +1; in a recent question, someone posted an actual program that exploited this feature. I was surprised that it worked. – Fred Foo Jan 31 '13 at 15:44
  • Documented in GCC in "6.19 Arrays of Variable Length" in **one sentence and one example** only: "As an extension, GCC accepts variable-length arrays as a member of a structure or a union. `void foo(int n) { struct S { int x[n]; }; }`". Documentation updated in **gcc 4.9**: https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Variable-Length.html https://github.com/gcc-mirror/gcc/commit/c051a2940b45464f0bd42959def3a10c91bf688b (svn 208836) PR c/37428 at 2014-03-26 by Marek Polacek of RedHat; https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37428 "GNU VLA-in-structure extension is undocumented" (2008-09) – osgx Mar 06 '17 at 19:38

3 Answers3

10

GCC does not allow it, compile with -std=c99 -pedantic-errors. A VLA inside a struct is apparently a (poorly documented) non-standard GNU C feature. See this.

Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 3
    Who ever used `-pedantic-errors`? Why this extension is so deeply hidden? No any user of gcc will know that this code is incorrect, because there is no any warning in default gcc mode. – osgx Jan 31 '13 at 15:51
  • 14
    @osgx: `-pedantic` is the flag to use if you want to compile your code strictly adhering to the standard. And the flag is pretty well known and documented feature. – Alok Save Jan 31 '13 at 15:54
  • 2
    @osgx One of the biggest flaws with GCC is indeed that it doesn't default to standard C, but to "GNU goo". If you are concerned with conformance and portability you should always compile with -pedantic and -Wall. I didn't try, but -Wall might perhaps also complain about the VLA. – Lundin Jan 31 '13 at 16:03
  • 3
    @osgx: `-pedantic` is well known; it causes gcc to at least warn about violations of the standard. `-pedantic-errors` is perhaps less widely known; it's like `-pedantic`, except that any violations are treated as fatal errors. One of the most important things to know about gcc is that it's not a standard-conforming C compiler by default. http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Standards.html#Standards – Keith Thompson Jan 31 '13 at 16:17
  • 1
    Unfortunately -pedantic also rejects some universally supported optional C features like bitfields with larger-than-int types. – R.. GitHub STOP HELPING ICE Jan 31 '13 at 16:24
  • @R.. There are plenty of embedded compilers which does not support that. Bit fields are 99% non-portable anyhow, so if someone would, for reasons unknown, use that completely superfluous feature of the C language, standard compliance is likely not a priority anyhow. – Lundin Jan 31 '13 at 19:34
  • @osgx they do that on purpose, to keep you from using other compilers. – MarcusJ Sep 20 '16 at 08:50
  • @AlokSave, Yes, there is `-pedantic`, but it will not help to catch VLAIS; it is `-pedantic-error` option only to get any error or warning on it. – osgx Sep 20 '16 at 23:26
4

The standard is pretty clear that VLAs are not allowed in a struct:

6.7.2.1 Structure and union specifiers

9 - A member of a structure or union may have any complete object type other than a variably modified type. [...]

Variably modified types are (as you might expect) those derived from a variable length array (e.g. by adding array dimensions or cv qualifiers):

6.7.6 Declarators

3 - [...] If, in the nested sequence of declarators in a full declarator, there is a declarator specifying a variable length array type, the type specified by the full declarator is said to be variably modified. Furthermore, any type derived by declarator type derivation from a variably modified type is itself variably modified.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
-2

The authors of the C89 Standard recognized that many implementations implemented useful features which might be impractical on other implementations, and recognized that as a good thing. The Standard was intended as a minimum set of requirements for implementations; it was never intended to discourage implementations from providing features beyond that.

The Standard requires that if a conforming implementation allows a variable-length array to be declared within a structure defined at block scope, it must either document such behavior as an extension or issue a diagnostic when code contains such a declaration. Since an implementation would be free to process the code however it likes after issuing such a diagnostic, whether or not it documents an extension, the requirement to document extensions can only be meaningfully applied to extensions which do not generate diagnostics. That in turn would suggest that such things must be allowable.

The Standard does require that extensions not adversely affect the behavior of any Strictly Conforming programs, but since no such program could contain a VLA declaration within a structure that requirement is not a problem here.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • It is still not documented "Feature" of GCC language (Actually of ADA influence on GCC IR design), and there are no errors until not widely known option `-pedantic-errors` is added. It is not a feature of the language, it is feature of compiler, and adding this feature in undocumented manner and not giving enough warning leads to wide usage of such feature (for example in Linux kernel) and *it is kind of [vendor lock-in](https://en.wikipedia.org/wiki/Vendor_lock-in)* as it prevents kernel from compilation with clang/icc/any other non-GCC-based compiler, resulting in GCC monopoly – osgx Mar 06 '17 at 19:16
  • No warnings with `-std=c99 -Wall -Wextra` with gcc; only warning with `-std=c99 -pedantic`: "`vlais.c:5:10: warning: a member of a structure or union cannot have a variably modified type [-Wpedantic]\n int params[argc]; // << Wat?`". Authors of kernel used this undocumented extension in several places in Linux kernel and changing code to standard-compatible take time and lot of extra effort: http://www.linuxplumbersconf.org/2013/ocw/sessions/1221 (they also says about clang "it doesn’t support VLAIS because it’s specifically disallowed by the C standard"). C99 allow VLA at the end of st – osgx Mar 06 '17 at 19:22
  • @osgx: The authors of the Standard made no effort to require that all implementations include all the features necessary to make them suitable for all purposes (or even *any* particular purpose). Most useful purposes that can be served using C will require features that are not present in all implementations, and the way to avoid vendor lock-in is for implementations to support useful features that are supported by other ones. The Standard was never intended to be used as an excuse not to support useful features or guarantees. – supercat Mar 06 '17 at 19:26
  • Also check http://thelinuxjedi.blogspot.ru/2014/02/why-vlais-is-bad.html about background of the "Feature" and effect of it. Also https://events.linuxfoundation.org/sites/events/files/slides/2015-Collab-LLVMLinux_0.pdf. It took several years (2012-2016) to remove most VLAIS from kernel, making it harder to be compiled with clang (and to find several security bugs with clang/sanitizers/fuzzers like syzkaller). – osgx Mar 06 '17 at 19:31
  • @osgx: I think VLAs should have been an optional feature from the get-go, and they should seldom be used outside fields where the aliasing assumptions that are enabled thereby are necessary to achieve acceptable performance (e.g. in high-end number crunching, a compiler can assume that `foo[r1][c1]` can't alias `foo[r2][c2]` if it knows that r1!=r2 *or* c1!=c2, but could not make such assumptions for `foo[r1*size+c1]` and `foo[r2*size+c2]`). That having been said, if useful code employs a construct, useful compilers should try to support it whether or not the Standard mandates it. – supercat Mar 06 '17 at 19:49
  • There was a bug in clang about "may try to support VLAIS" and they says that it can't be expressed in LLVM IR correctly, as LLVM IR was designed for C/C++ language, not for ADA like GCC's IRs. One of bugs: https://bugs.llvm.org//show_bug.cgi?id=9254 "*error: fields must have a constant size: 'variable length array in structure' extension will never be supported ... Eli Friedman 2011: Implementing this would be a crapload of verification work to make sure all the places that handle types handle structs with non-constant size, for handling a few rare constructs like this.*". – osgx Mar 06 '17 at 19:57
  • And you just advocates GCC's vendor lock-in by calling several good compilers (llvm+clang, intel, ..) as not "useful compilers" when they supports C/C++ as described in standards, but they are not hybrid of Ada/C compiler. – osgx Mar 06 '17 at 19:58
  • 1
    @osgx: I said "should try". That is not a particularly strong imperative. My point is that if a feature would be useful and a compiler could support it easily, it should not refrain from doing so *merely* because the Standard doesn't encourage such support. On the other hand, I think the authors of both gcc and clang have a tendency to regard the Standard as limiting what programmers should expect from implementations, even though C89 was never meant that way, and many of the later standards have kept parts of C89 which could not sensibly be interpreted that way. – supercat Mar 06 '17 at 20:12