Restrict accessing arrays by wrong index

465 views Asked by At

I’m interested in adding a rule to coverity checkers and want to consult if it’s feasible and what is needed to do to achieve. I’m talking about C programming, and I want to restrict the access to arrays using a defined enumerator – and not any integer index.

For example I have two arrays: oranges and apples of sizes 5 and 10 cells accordingly.

In order to avoid misuse of the arrays, I want to define two enums (or typedefs if needed), one for oranges and one for apples:

Enum apples {
    A0 = 0,
    A1 = 1,
    A2 = 2,
    A3 = 3,
    A4 = 4,
}

Enum oranges {
    O0 = 0,
    O1 = 1,
    O2 = 2,
    O3 = 3,
    O4 = 4,
    O5 = 5,
    O6 = 6,
    O7 = 7,
    O8 = 8,
    O9 = 9,
}

And I want to add a rule to coverity that checks each access to these arrays. For example:

Apples[A4];  //success

Apples[O0]; // coverity error

Apples[2]; // coverity error

Is it possible to add such rule ?

3

There are 3 answers

0
Nitinkumar Ambekar On

//USING MODULUS OPERATOR TO AVOID OUT OF BOUND

#include <stdio.h>
#define LIMIT 5
int main()
{

         char array[LIMIT] = {'A', 'B', 'C', 'D', 'E'};
         for(int i = 0; i < LIMIT + 3; i++)
                 printf("ELEMENT = '%c'\n", array[i%LIMIT]);

         return 0;
}
1
Alex Celeste On

To do something like this in pure C (rather than using an external tool), you could use structs instead of enums to represent your allowed index range. Structs are strongly-typed and so the type system will prevent you from using an indexer intended for one array to access the other.

There are several ways you could go about this - you could put the int index inside the struct, or (assuming the element range is contiguous) you could make your safety even more rigid by using the struct identities directly rather than any exposed integers at all:

typedef struct { int UNUSED; } appleI;
typedef struct { int UNUSED; } orangeI;

const appleI apples[5] = { };

const orangeI oranges[10] = { };

apple_t * Apples(appleI * i) {    //The actual array is hidden from view
    static apple_t _Apples[] = { ... };
    return &_Apples[i - &apples[0]];
}

orange_t * Oranges(orangeI * i) {
    static orange_t _Oranges[] = { ... };
    return &_Oranges[i - &oranges[0]];
}

#define A0 (&apples[0])
#define A1 (&apples[1])
// ...etc

...
orange_t myOrange = ...;
*Oranges(O2) = myOrange;
apple_t myApple = *Apples(A3);
  • you can potentially add a range check to the middle of the "array" functions, to ensure no new instances of the index types are used (which would certainly be an error - these types should be opaque to user code)

  • you can still use A0 + 1 and so on

  • this stuff should be fairly easy for a powerful compiler to inline and reduce down to nothing

2
Mihail Feraru On

You can make a function what check this, if it know the length. I don't see another solution, because C doesn't check out of index.

<array_type> accessArray(<array_type> array, int index, int len)
{
    if (index > len || index < 0) {
        return <error_value>; // return an error value set by you 
    } else { 
        return array[index];
    }
}