Bug 50584 - No warning for passing small array to C99 static array declarator
Summary: No warning for passing small array to C99 static array declarator
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
: 77577 (view as bug list)
Depends on:
Blocks: 67793
  Show dependency treegraph
 
Reported: 2011-09-30 17:05 UTC by Ian Lance Taylor
Modified: 2018-02-07 15:36 UTC (History)
11 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2015-07-03 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ian Lance Taylor 2011-09-30 17:05:20 UTC
C99 introduced the idea of using static in an array declarator in a function prototype parameter.  My reading of the standard is that using static means that the actual argument must be at least that size.  GCC should at least issue a warning when that requirement is clearly violated.

For example, this program


extern void bar (void *a[static 6]);
void foo() {
  void *a1;
  void *a2[5];
  void *a3[6];
  void *a4[10];

  bar (&a1);
  bar (a2);
  bar (a3);
  bar (a4);
}

should issue a warning, or perhaps even an error, for the first two calls to bar, as the compiler can clearly see that the values are not large enough.
Comment 1 Andi Kleen 2013-02-19 06:51:18 UTC
Confirmed. Still happens with 4.7/4.8
Comment 2 Malcolm Inglis 2013-08-14 04:46:50 UTC
GCC 4.8.1 is still failing to warn for static array indices in function parameters.

The C99 status pages say this feature has been done since 3.1: http://gcc.gnu.org/gcc-3.1/c99status.html

Was there a regression?
Comment 3 joseph@codesourcery.com 2013-08-21 22:34:03 UTC
The point of this language feature is for optimization, not diagnostics - 
but there is no requirement for either; GCC does all the checks required 
by C99 on the contexts in which [static] may be used.  c99status.html 
specifically notes that it is not used for optimization.
Comment 4 Malcolm Inglis 2013-09-25 10:21:42 UTC
I don't have a copy of the C99 standard, but IBM says [1] that if the function is called with a pointer to a smaller array than specified with `static`, then the behavior is undefined. Ergo, there should be a warning.

Could someone change the status of this bug?

I'm about 60% sure that I once played around with this in GCC, and it correctly reported an error. This wouldn't have been too long ago; maybe 4.6 or even 4.7.

Clang emits a warning for this. [2]

I think this is a fantastic language feature. It's a shame GCC doesn't support it yet.

[1]: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/topic/com.ibm.xlcpp8a.doc/language/ref/param_decl.htm

[2]: http://hamberg.no/erlend/posts/2013-02-18-static-array-indices.html
Comment 5 jimis 2014-04-10 12:28:36 UTC
I'm currently using this C99 feature. A warning would be nice if NULL or small arrays are passed.
Comment 6 Marek Polacek 2014-04-10 12:51:16 UTC
I don't recommend this kind of usage of the static keyword.  There was even the possibility of removing/deprecating this feature.  Quoting from DR#205:
"There was a unanimous vote that the feature is ugly, and a good consensus that its incorporation into the standard at the 11th hour was an unfortunate decision."
Comment 7 Serg Iv 2015-07-03 01:20:22 UTC
Some excerpts from the C11 standard:

/-----
If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
\-----

And another one:

/-----
The following are all compatible function prototype declarators:
[..snip..]
void f(double a[restrict 3][5]);
void f(double a[restrict static 3][5]);

(Note that the last declaration also specifies that the argument corresponding to a in any call to f must be a non-null pointer to the first of at least three arrays of 5 doubles, which the others do not.)
\-----

I'm not sure about warnings (the meaning of the word "shall" is unclear for me), but IMO according to the standard null-pointers should issue an *error*.
Comment 8 Serg Iv 2015-07-03 01:41:25 UTC
Forgot to say that C99 standard has the same sentences.

Useful links:

C99 draft http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

C11 draft http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf
Comment 9 Manuel López-Ibáñez 2015-07-03 09:34:14 UTC
(In reply to Malcolm Inglis from comment #4)
> Could someone change the status of this bug?

Notwithstanding whether the feature is pretty or ugly, GCC does accept this code and warnings for undefined behavior, when possible, are desired. Thus, confirmed. 

This does not mean anyone is going to work on fixing this. Please, if you are using this feature and would like to see this warning in GCC, please consider contributing it: https://gcc.gnu.org/wiki/GettingStarted#Basics:_Contributing_to_GCC_in_10_easy_steps

If you start working on this, it would be good to say so here.
Comment 10 Serg Iv 2015-07-03 12:50:31 UTC
Some thoughts after I read C99 rationale.

Actually, [static N] it's a PROMISE to a compiler, that programmer will always provide N pieces of data. *ALWAYS*.
Therefore compiler can do with this data whatever it wants. It can, for instance, copy it (all N elements) somewhere to some local cache for optimization. Or send it into the space towards the Ape Planet to use brand new Appe book for calculations.
If the programmer didn't provide N pieces of the information - we may have segfault, crash, bsod or nuclear war, it depends. It not a compiler's headache, it's a programmer fault.

So, IMO the right way for GCC is 
a) if it get NULL pointer through all optimization or smaller array is provided - error in compile time
b) if func's supplied with an array lenght >= N, compile without errors and warnings
c) otherwise - warning.
Comment 11 joseph@codesourcery.com 2015-07-24 22:52:16 UTC
On Fri, 3 Jul 2015, sergei.ivn+bugzilla at gmail dot com wrote:

> Some excerpts from the C11 standard:
> 
> /-----
> If the keyword static also appears within the [ and ] of the array type
> derivation, then for each call to the function, the value of the corresponding
> actual argument shall provide access to the first element of an array with at
> least as many elements as specified by the size expression.
> \-----

This is in a Semantics section, not Constraints.

> I'm not sure about warnings (the meaning of the word "shall" is unclear for
> me), but IMO according to the standard null-pointers should issue an *error*.

"shall" is defined in clause 4, paragraph 2: 'If a "shall" or "shall not" 
requirement that appears outside of a constraint or runtime-constraint is 
violated, the behavior is undefined.'

In this case, the "shall" relates to a property of an execution of a 
program, not a property of the program itself.  Thus, undefined behavior 
only occurs on such an execution.  In particular, a program with such a 
call inside if (0) - or in any code that the compiler cannot prove will 
always be executed for all executions of the program - must *not* produce 
an error at compile time.  To quote the response to DR#109, "A conforming 
implementation must not fail to translate a strictly conforming program 
simply because some possible execution of that program would result in 
undefined behavior.".

Some such cases of runtime-undefined behavior get compiled into aborts, 
but this is only valid if the abort only occurs when the undefined 
function call would definitely be executed - not, for example, before the 
evaluation of another argument to the function that might exit the program 
or call longjmp (see previous bug fixes in this regard).
Comment 12 nsz 2016-01-07 12:25:16 UTC
(1) consider a simplified example from bug 17308

  __attribute__((nonnull(1)))
  void foo(char *bar) { if (!bar) __builtin_abort(); }

with gcc -O2 -fno-asynchronous-unwind-tables -fomit-frame-pointer -std=c99 -Wall
i get warnings:

  a.c: In function 'foo':
  a.c:2:27: warning: nonnull argument 'bar' compared to NULL [-Wnonnull]
   void foo(char *bar) { if (!bar) __builtin_abort(); }
                           ^
and asm code:

  foo:
  	rep ret

(2) however code with similar semantics:

  void foo(char bar[static 1]) { if (!bar) __builtin_abort(); }

gives no warnings and the generated asm is

  foo:
  	testq	%rdi, %rdi
  	je	.L7
  	rep ret
  .L7:
  	pushq	%rax
  	call	abort

the code in (2) should at least imply nonnull argument, since this is
the idiomatic nonnull annotation in c since c99.

(unfortunately it does not work for void* arguments, otherwise i think
it is useful for static analysis, but it won't be used in practice
unless compilers make use of it.)
Comment 13 Markus Trippelsdorf 2016-09-13 06:16:05 UTC
*** Bug 77577 has been marked as a duplicate of this bug. ***
Comment 14 Fredrik Hederstierna 2017-05-16 14:21:22 UTC
Still present in GCC-7.1.0

Simple test code:

-------------------------------------
int s[1] = { 1 };

void test(int v[static 2])
{
  printf("%d\n", v[1]);
  v[1] = 0;
}

int main(void)
{
  test(s);
  return 0;
}

-------------------------------------
No warnings by GCC:

> gcc -c test.c -W -Wall -Wextra -Warray-bounds -O2 -std=c99

-------------------------------------
But with CLANG-3.8.0 we get warnings:

> clang -c test.c

test.c:13:3: warning: array argument is too small; contains 1 elements, callee
      requires at least 2 [-Warray-bounds]
  test(s);
  ^    ~
test.c:5:15: note: callee declares array parameter as static here
void test(int v[static 2])
              ^~~~~~~~~~~
1 warning generated.