Sourodeep Basu
Sourodeep Basu

Reputation: 11

Is it possible to define any size array in a C function call?

does the below code is safe to use? somehow I think this not right way to do. I know a better way is malloc(), realloc(). But I want to understand where this code posses most risk. As compiler does not know the allocation size, how the stack size will be defined ?

int array_call(int k)

{
   int temp[k];
   int = 0;
   int i = 0;
   for (i = 0;i<k;i++)
       {
         temp[i]=i;
       }
    return k;

}

int main()
{

int n;
scanf("%d", &n);
n=array_call(n);

}

Upvotes: 0

Views: 118

Answers (3)

John Bollinger
John Bollinger

Reputation: 180286

does the below code is safe to use?

No.

somehow I think this not right way to do. I know a better way is malloc(), realloc(). But I want to understand where this code posses most risk.

Risk #1: the feature you are relying upon, variable-length arrays, is optional in C11 and later, and absent (at least not standardized) in C90. Only in C99 is it both standard and mandatory. Many C implementations you will meet implement it, but there are notable ones that do not. Your code will not compile at all on the latter.

Risk #2: C does not specify how automatic VLAs are implemented, but it is common for them to be allocated on the stack. In such implementations it is relatively easy to cause the program to fail with a stack overflow by providing too large a value of n. There is usually (much) more space available for dynamic allocation with malloc() &co., but even if there weren't, you can at least detect and recover from a malloc() failure. Similar applies to the possibility that n is given as a negative number.

Risk #3: you are using unvalidated user input in a sensitive way. This is a major failing of secure programming protocol.

As compiler does not know the allocation size, how the stack size will be defined ?

You're assuming that there is a stack, and that that's where the VLA will go. Neither is guaranteed. Nor is there a requirement for a particular behavior in those implementations where both of those assumptions hold. In practice, however, the compiler is reasonably likely to allocate VLA members at the top of the stack, above non-VLA members, and simply to adjust the stack pointer appropriately for the value of n. It's a little trickier if there are multiple VLAs, but totally doable. This is among the least of the problems involved.

Upvotes: 1

John Bode
John Bode

Reputation: 123468

This is an example of a variable-length array (VLA), where the array size isn't known until runtime. This feature was introduced in the 1999 revision of the language, but was made optional in the 2011 revision.

So, the first risk is that VLAs are not universally supported - this code may not compile on some platforms. On C2011 and later, you'll want to check if the __STDC_NO_VLA__ feature macro has been defined before trying to use them, something like

#if defined( __STDC_NO_VLA__ )
  int *temp = malloc( sizeof *temp * k );
#else
  int temp[k]; 
#endif

/** do stuff with temp **/

#if defined( __STDC_NO_VLA__ )
  free( temp );

The second main risk is that VLAs cannot be arbitrarily large - many (if not most) implementations try to allocate VLA space from the stack, and stack space tends to be limited. If k is too large1 you will likely get some kind of unrecoverable runtime error.

VLAs may not be declared at file scope or with the static keyword, nor may they be members of struct or union types.


  1. The exact value of "too large" depends on the platform, compiler, source code, etc.

Upvotes: 1

DaveHowell
DaveHowell

Reputation: 1264

If you're using a compiler that doesn't support VLAs (Variable Length Arrays), you might just have that function allocate, and return, an array with the given size.

int *NewInitedArrayWithCount( unsigned int arrayCount )
{
   int *array = (int *) malloc( arrayCount * sizeof( int ));
   if ( array != NULL )
   {
      for ( int i = 0; i<arrayCount; i++ )
       {
            array[i] = (int) i;
       }
   }
   return array;
}

int main()
{
   unsigned int arrayCount;
   scanf( "%u", &arrayCount );
   int *array = NewInitedArrayWithCount( arrayCount );

   // Do stuff

   if ( array != NULL )
      free( array );
   return 0;
}

Upvotes: 0

Related Questions