【问题标题】:Accessing array beyond the limit访问数组超出限制
【发布时间】:2011-04-09 04:09:21
【问题描述】:

我有两个大小为 100 的字符数组(char array1[100],char array2[100])。现在我只想检查是否有人正在访问超出限制的数组。这是必要的,因为假设为 array1 和 array2 分配的内存是连续的,因为 array1 完成然后 array2 开始。现在如果有人写:array1[101],从概念上讲它是错误的,但编译器会给出警告但不会崩溃。那么我该如何检测并解决这个问题呢?

更新 1:

我已经有了第 15,000 行的代码。对于那个代码,我必须检查这个条件,我可以调用我的函数,但不能更改编写的代码。请根据这个建议我。

【问题讨论】:

  • 这取决于您使用的语言...
  • 我使用的是c++语言。

标签: c++ arrays


【解决方案1】:

如果您使用 boost::array 或类似方法,如果超出数组边界,您将收到异常 range_error。 http://www.boost.org/doc/libs/1_44_0/doc/html/boost/array.html。 Boost 太棒了。

【讨论】:

    【解决方案2】:

    如果您针对您的代码运行静态分析器(即 cppcheck),则会出现边界错误 http://en.wikipedia.org/wiki/User:Exuwon/Cppcheck#Bounds_checking

    要解决它...最好使用某种容器(即 std::vector)或编写包装器

    【讨论】:

      【解决方案3】:

      如果您使用 C++,您可以编写一个快速包装类。

      template<typename T, int size> class my_array_wrapper {
          T contents[size];
      public:
          T& operator[](int index) {
              if (index >= size)
                  throw std::runtime_error("Attempted to access outside array bounds!");
              if (index < 0)
                  throw std::runtime_error("Attempted to access outside array bounds!");
              return contents[index];
          }
          const T& operator[](int index) const {
              if (index >= size)
                  throw std::runtime_error("Attempted to access outside array bounds!");
              if (index < 0)
                  throw std::runtime_error("Attempted to access outside array bounds!");
              return contents[index];
          }
          operator T*() {
              return contents;
          }
          operator const T*() const {
              return contents;
          }
      };
      
      my_array_wrapper<char, 100> array1;
      array1[101]; // exception
      

      问题已解决,但如果您通过指针衰减访问,则不会进行边界检查。您可以使用 boost::array 预先提供的解决方案。

      【讨论】:

      • 为什么要重新发明轮子?这个问题的现有解决方案已被证明并保存 OP 测试他/她自己的版本。
      • 我会抛出out_of_range,而不是runtime_error,就像vector::at() 那样。另外,我会制作size_t 类型的indexsize,所以我不必与0 进行比较。
      • 嗯。它不应该是理想主义的完美工作代码,而是一个起点。
      【解决方案4】:

      如果您使用的是 C++ 而不是 C,有什么理由不能使用 std::vector?如果用户超出您的范围,这将为您提供界限检查。我在这里遗漏了什么吗?

      首先阻止用户直接访问集合不是明智的吗?

      【讨论】:

        【解决方案5】:

        在 C/C++ 中,没有通用的解决方案。你不能在编译时这样做,因为在 C 中有太多改变内存的方法。示例:

        char * ptr = &array2;
        ptr = foo(ptr); // ptr --;
        

        ptr 现在包含一个有效地址,但该地址在array2 之外。这可能是一个错误或您想要的。 C 无法知道(在 C 中没有办法说“我想要它”),所以编译器无法检查它。傻傻的:

        char * array2 = malloc(100);

        C 编译器如何知道您将内存视为 char 数组并在您编写 &amp;array2[100] 时希望收到警告?

        因此,大多数解决方案都使用“mungwalls”,即当您调用 malloc() 时,它们实际上会分配比您要求的多 16/32 字节:

        malloc(size) {
            mungwall_size = 16;
             ptr = real_malloc(size + mungwall_size*2);
             createMungwall(ptr, mungwall_size);
             createMungwall(ptr+size, mungwall_size);
             return ptr+size;
        }
        

        free() 中,它将检查分配的内存区域之前和之后的 16 个字节是否未被触及(即 mungwall 模式仍然完好无损)。虽然并不完美,但它会使您的程序更早崩溃(并希望更接近错误)。

        您也可以使用特殊的 CPU 命令来检查所有内存访问,但这种方法会使您的程序比现在慢 100 到 100 万倍。

        因此,C 之后的语言不允许使用指针,这意味着“数组”是具有大小的基本类型。现在,您可以通过简单的比较来检查每个数组访问。

        如果你想用 C 语言编写保存的代码,你必须模仿它。创建一个数组类型,永远不要使用指针或char * 作为字符串。这意味着您必须始终转换您的数据类型(因为所有库函数都使用const char * 表示字符串)但它使您的代码更安全。

        语言确实会老化。 C 现在已经 40 岁了,我们的知识也在不断发展。它仍然在很多地方使用,但它不再是首选。这同样适用于(在较小的范围内)C++,因为它具有 C 的相同基本缺陷(即使您现在拥有可以解决其中许多问题的库和框架)。

        【讨论】:

        • 投反对票。在 C++ 中,很容易编写一个包装。说在 C++ 中没有通用解决方案是完全错误的。
        • 我说“有很多框架可以解决这些问题”。但是很多愚蠢的 C 代码确实用 C++ 编译,并且通过使用错误的参数调用错误的函数,你会得到一种建造纸牌屋的感觉。
        【解决方案6】:

        我对此的最初反应是将对这些数组的访问包装在一个函数或方法中,并将索引作为参数发送。如果索引超出范围,则引发异常或以其他方式报告错误。

        编辑: 这当然是一种运行时预防。如果编译器无法为您检查,不知道如何在编译时检查。此外,正如 Kolky 已经指出的那样,如果我们知道您使用的是哪种语言,那么回答这个问题会更容易。

        【讨论】:

          【解决方案7】:

          大多数现代语言都会检测到这一点并阻止它发生。 C 及其派生词无法检测到这一点,而且基本上也无法检测到这一点,因为您可以通过多种方式访问​​内存,包括裸指针。如果您可以限制访问内存的方式,那么您可以使用函数或其他东西来检查您的访问。

          【讨论】:

            猜你喜欢
            • 2013-09-14
            • 1970-01-01
            • 2021-10-04
            • 2018-09-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多