Question

Are there any tools (preferably on linux) that can warn when an argument is defined as a smaller array then the prototype specifies?

eg:

void somefunc(float arg[10]);  /* normally this would be defined in a header */

void my_func(void)
{
    float arg[2];
    somefunc(arg);  /* <-- this could be a warning */
}

I realize this isn't invalid code but it could resolve some common mistakes if it were possible to warn of it (ran into one of these bugs recently).

Some tools (clang static checker for eg), will warn if the function is in the same file and sets a value outside the array bounds, but I was wondering if anything will warn if the arg is smaller then the prototype alone.

I've used cppcheck, clang, smatch, splint, gcc's -Wextra... but none complain of this.

Was it helpful?

Solution 3

Since asking this question, cppcheck has added this feature in response to my suggestion (thanks guys!),

Commit: https://github.com/danmar/cppcheck/commit/7f6a10599bee61de0c7ee90054808de00b3ae92d

Issue: http://sourceforge.net/apps/trac/cppcheck/ticket/4262

At the time of writing this isn't yet in a release, but I assume it will be in the next release.

OTHER TIPS

The value in the prototype has no meaning to the compiler and is ignored! The function declared above is equivalent to

void somefunc(float* arg);

and

void somefunc(float arg[]);

When using C++ you can deal with the size restriction at compile-time using references. If you really mean to have an array of 10 floats, you can pass it by reference which will enforce that the size is correct:

void somefunc(float (&arg)[10]);

However, this will prevent bigger arrays from being passed. You can play with a template forwarding function if you want to pass bigger arrays:

void somefunc_intern(float* arg);
template <int Size>
typename std::enable_if<(10 <= Size)>::type
somefunc(float (&arg)[Size]) {
    somefunc_intern(arg);
}

Of course, this won't generate a warning but an error if a too small array is passed.

In the C language, the float arg[10] parameter array bounds are merely stylistic: it is a hint to the programmer, not the compiler. Since C has weak type checking, you can pass any kind of float pointer or array to the function. One may argue and say that a programmer who doesn't read the function documentation before passing parameters to it, is asking for trouble. But there is of course always the potential for accidental bugs.

Good compilers will warn against this. If you have a bad compiler, which does not warn, you should indeed consider using an external static analysis tool, they are always notoriously picky about suspicious type conversions. Lint comes in a Linux version, I haven't used it, but it is known as an affordable alternative to the big and complex ones.

Theoretically, you could write code that will cause the compiler to produce more warnings, but it will obfuscate the program. I wouldn't recommend it, it would look like:

void somefunc(float (*arr_ptr)[10])
{
  float* arg = *arr_ptr;
  ...
}

int main()
{
  float ten[10];
  float two[2];

  somefunc(ten);  // warning
  somefunc(&ten); // warning
  somefunc(two);  // warning
  somefunc(&two); // warning

  float (*ten_ptr)[10] = &ten;
  float (*two_ptr)[2] = &two;

  somefunc(ten_ptr) // ok
  somefunc(two_ptr) // warning

}

A perfectly ordinary C++ compiler will give you a compile error if you use std::array<N> instead or C arrays.

So just do that?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top