public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* array bounds, sanitizer, safe programming, and cilk array notation
@ 2015-01-26 19:54 Martin Uecker
  2015-01-27  0:08 ` Joseph Myers
  2015-02-21 15:21 ` Marek Polacek
  0 siblings, 2 replies; 7+ messages in thread
From: Martin Uecker @ 2015-01-26 19:54 UTC (permalink / raw)
  To: gcc Mailing List
  Cc: Jeff Law, Joseph Myers, Jakub Jelinek, Marek Polacek,
	Florian Weimer, Balaji V. Iyer


Hi all,

I am writing numerical code, so I am trying to make the use 
of arrays in C (with gcc) suck a bit less. In general, the long term
goal would be to have either a compile-time warning or the possibility
to get a run-time error if one writes beyond the end of an array as 
specified by its type.

So one example (see below) I looked at is where I pass an array of
too small size to a function, to see how see can be diagnosed. In some
cases, we can get a runtime error with the address sanitizer, but this
is fairly limited (e.g. it does not work when the array is embedded
in a struct) and I also got mixed results when the function
is inlined.

For pointers to arrays with static size one can get an "incompatible
pointer" warning - which is nice. With clang, I also get warning for 
pointers which are declared as array parameters and use the 'static' 
keyword to specify a minimum size. This a diagnostic we are currently
missing.

The next step would be to have diagnostics also for the VLA
case if the size is known at compilation time (as in the
example below) and a run-time error when it is not (maybe 
with the undefined behaviour sanitizer?).

If we have the later, I think this might also help with safer 
programming in C, because one would get either a compile time or 
runtime error when I passing a buffer which is too small to
a function. For example, snprintf could have a prototype like
this:

int snprintf(size_t size; char str[static size], size_t size, 
  const char *format, ...);

That VLAs essentially provide the bounded pointer type C is
missing has been pointed out before, e.g. there was a proposal
by John Nagle, although he proposed rather intrusive language
changes (e.g. adding references to C) which are not necessary
in my opinion:

https://gcc.gnu.org/ml/gcc/2012-08/msg00360.html


Finally, what is missing is a way to diagnose problems inside
the called functions. -Warray-bounds=2 (with my recently
accepted patch) helps with this, but - so far - only for static 
arrays:

void foo(int (*x)[4])
{
	(*x)[4] = 5;	// warning
}

It would be nice to also have these warning and runtime errors
(with the undefined behaviour sanitizer) for VLAs. 

Finally, I think we should have corresponding warning also
for pointers which are declared as array parameters:

void foo2(int x[4])
{
	x[4] = 5;
}

The later does not currently produce a warning, because x
is converted to a pointer and the length is ignored. 

If it is not possible to have warning here for compatibility
reasons, one possibility is to have an extension similar to 
'static' which makes 'x' a proper array in the callee, e.g. 
something like:

void foo2(int x[array 4])
{
	// x is now of type int[4] and not int*

	x[4] = 5; // error
}

The semantics would be that the array is still passed as
a pointer but the type of x would be int[4]. Because it
immediately decays into a pointer when used, no code generation
changes would be required (except maybe when looking at the
type with sizeof and _Generic).

Another reason I like this is because Cilk array notation
currently requires the length to be specified for 'x' because
it is a pointer and not an array. If x would be an array,
something like this would work:

void foo2(int x[array 4])
{
	x[:] = 1;
}

In fact, the documentation for Cilk as such examples
(without the array keyword), and I guess this works on the
intel compiler but not on gcc.

I am willing to spend some (limited) time on all of this, but
I thought I ask for comments first. I appreciate any feedback,
suggestions, and help!

Cheers,
Martin




// file 1
extern void bar(int x[static 5])
{
	for (int i = 0; i < 5; i++)
		x[i] = 1;
}

extern void bar2(int (*x)[5])
{
	for (int i = 0; i < 5; i++)
		(*x)[i] = 1;
}

// file 2

#include <stdio.h>



extern void bar(int x[static 5]);
extern void bar2(int (*x)[5]);




int main()
{
	int x[4] = { 0 };
	bar(x);		// warning only with clang (found by asan)
	bar2(&x);	// warning (found by asan)
	
	int c = 4;
	int y[c];
	
	for (int i = 0; i < c; i++)
		y[i] = 0;

	bar(y);		// not diagnosed (found by asan)
	bar2(&y);	// not diagnosed (found by asan)

	struct foo {
		int z[4];
		int bar;
	} zz = { { 0 }, 0 };

	bar(zz.z);	// warning only with clang
	bar2(&zz.z);	// warning

	printf("%d %d %d %d\n", x[0], x[1], x[2], x[3]);
	printf("%d %d %d %d\n", y[0], y[1], y[2], y[3]);
	printf("%d %d %d %d\n", zz.z[0], zz.z[1], zz.z[2], zz.z[3]);
}





^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-02-24  1:46 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-26 19:54 array bounds, sanitizer, safe programming, and cilk array notation Martin Uecker
2015-01-27  0:08 ` Joseph Myers
2015-02-21 15:41   ` Marek Polacek
2015-02-23 17:53     ` Joseph Myers
2015-02-21 15:21 ` Marek Polacek
2015-02-22  0:41   ` Martin Uecker
2015-02-24  1:46     ` questionable checks for flexible array members in c-ubsan.c and tree-vrp.c (was: Re: array bounds, sanitizer, safe programming, and cilk array notation) Martin Uecker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).