【问题标题】:Restrict accessing arrays by wrong index通过错误的索引限制访问数组
【发布时间】:2014-10-26 16:16:03
【问题描述】:

我有兴趣向覆盖检查器添加规则,并想咨询它是否可行以及需要做什么才能实现。 我说的是 C 编程,我想使用定义的枚举器来限制对数组的访问——而不是任何整数索引。

例如,我有两个数组:orangesapples,大小分别为 5 和 10 个单元格。

为了避免数组的误用,我想定义两个枚举(或 typedef,如果需要),一个用于oranges,一个用于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,
}

我想添加一个规则来检查对这些数组的每次访问。 例如:

Apples[A4];  //success

Apples[O0]; // coverity error

Apples[2]; // coverity error

是否可以添加这样的规则?

【问题讨论】:

  • 供您参考,C 不会检查数组索引是否越界。
  • 我知道,如果需要,我可以检查覆盖率。关于 out-of-band ,默认检查覆盖率。
  • @Jayesh:确实,因此而浪费的开发/质量保证/支持成本的综合成本无疑可以资助几次载人火星任务,包括回程;)

标签: c arrays coverity out-of-band


【解决方案1】:

如果它知道长度,你可以创建一个检查这个的函数。我没有看到另一种解决方案,因为 C 没有检查出索引。

<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];
    }
}

【讨论】:

  • 你如何区分零表示错误和0表示正常值?
  • 这仅检查我已经拥有覆盖范围的越界,我想为覆盖范围添加更多规则以捕捉相反的情况。
【解决方案2】:

//使用模数运算符避免越界

#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;
}

【讨论】:

    【解决方案3】:

    要在纯 C 中(而不是使用外部工具)执行此类操作,您可以使用结构而不是枚举来表示允许的索引范围。结构是强类型的,因此类型系统会阻止您使用旨在用于一个数组的索引器来访问另一个数组。

    有几种方法可以解决这个问题 - 你可以将 int 索引放在结构中,或者(假设元素范围是连续的)你可以通过直接使用结构标识而不是任何暴露的标识来提高安全性整数:

    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);
    
    • 您可能会在“数组”函数的中间添加范围检查,以确保不使用索引类型的新实例(这肯定是一个错误 - 这些类型对用户代码应该是不透明的)

    • 你仍然可以使用A0 + 1等等

    • 对于一个强大的编译器来说,这些东西应该很容易内联并减少到无

    【讨论】:

    • 感谢您的建议,看起来不错。但是我已经定义了数组并且我无法更改它们的定义的问题。此外,我说的是一个超过 1 人将开发的 FW,因此我希望直接使用数组/索引,但即使使用像 Coverity 这样的外部工具也能够发现任何误用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多