Main Content

Incorrect syntax of flexible array member size

Flexible array member defined with size zero or one

Description

This defect occurs when you do not use the standard C syntax to define a structure with a flexible array member.

Since C99, you can define a flexible array member with an unspecified size. For instance, desc is a flexible array member in this example:

struct record {
    size_t len;
    double desc[]; 
};
Prior to C99, you might have used compiler-specific methods to define flexible arrays. For instance, you used arrays of size one or zero:
struct record {
    size_t len;
    double desc[0]; 
};
This usage is not compliant with the C standards following C99.

Risk

If you define flexible array members by using size zero or one, your implementation is compiler-dependent. For compilers that do not recognize the syntax, an int array of size one has buffer for one int variable. If you try to write beyond this buffer, you can run into issues stemming from array access out of bounds.

If you use the standard C syntax to define a flexible array member, your implementation is portable across all compilers conforming with the standard.

Fix

To implement a flexible array member in a structure, define an array of unspecified size. The structure must have one member besides the array and the array must be the last member of the structure.

Examples

expand all

#include <stdlib.h>
  
struct flexArrayStruct {
  int num;
  int data[1];
};

unsigned int max_size = 100;
 
void func(unsigned int array_size) {
  if(array_size<= 0 || array_size > max_size)  
      exit(1);
  /* Space is allocated for the struct */
  struct flexArrayStruct *structP
    = (struct flexArrayStruct *)
     malloc(sizeof(struct flexArrayStruct)
          + sizeof(int) * (array_size - 1));
  if (structP == NULL) {
    /* Handle malloc failure */
    exit(2);
  }
   
  structP->num = array_size;
 
  /*
   * Access data[] as if it had been allocated
   * as data[array_size].
   */
  for (unsigned int i = 0; i < array_size; ++i) {
    structP->data[i] = 1;
  }
  
  free(structP);
}

In this example, the flexible array member data is defined with a size value of one. Compilers that do not recognize this syntax treat data as a size-one array. The statement structP->data[i] = 1; can write to data beyond the first array member and cause out of bounds array issues.

Correction — Use Standard C Syntax to Define Flexible Array

Define flexible array members with unspecified size.

#include <stdlib.h>
  
struct flexArrayStruct{
  int num;
  int data[];
};

unsigned int max_size = 100;
 
void func(unsigned int array_size) {
  if(array_size<=0 || array_size > max_size)  
      exit(1);
  
  /* Allocate space for structure */
  struct flexArrayStruct *structP
    = (struct flexArrayStruct *)
    malloc(sizeof(struct flexArrayStruct)
         + sizeof(int) * array_size);
         
  if (structP == NULL) {
    /* Handle malloc failure */
    exit(2);
  }
 
  structP->num = array_size;
 
  /*
   * Access data[] as if it had been allocated
   * as data[array_size].
   */
  for (unsigned int i = 0; i < array_size; ++i) {
    structP->data[i] = 1;
  }
  
  free(structP);
}

Result Information

Group: Good Practice
Language:C (checker disabled if the analysis runs on C90 code indicated by the option -c-version c90)
Default: Off
Command-Line Syntax: FLEXIBLE_ARRAY_MEMBER_INCORRECT_SIZE
Impact: Low

Version History

Introduced in R2018b