首页 > 解决方案 > Ada 中的无约束数组可以安全使用吗?

问题描述

我正在阅读 Ada 中的数组类型,发现有趣的是,与 C++ 不同,该语言允许它们的大小在编译时是未知的。我不确定它们是如何实现的,所以我写了一个小测试:

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Command_Line; use Ada.Command_Line;

procedure Main is
   type Data is array (1 .. 131_072) of Integer;
   type Vector is array (Positive range <>) of Data;
   Sequence : Vector (1 .. Argument_Count);
begin
   for I in Sequence'Range loop
      Sequence (I) := (others => I);
      Put (Integer'Image (Sequence (I)(1)));
   end loop;
end Main;

然后尝试使用可变长度数组在 C 中复制此代码:

#include <stdio.h>

struct data {
    int x[131072];
};

int main(int argc, char** argv) {
    (void)argv;
    struct data sequence[argc - 1];
    for (int i = 0; i < argc - 1; i++) {
        for (int j = 0; j < 131072; j++)
            sequence[i].x[j] = i;
        printf("%i ", sequence[i].x[1]);
    }
}

gnatmake -gnato -fstack-check -gnat2012 -gnata -O3 main.adb -o main我用和编译gcc -O3 -Wall -Werror -Wextra -pedantic cmain.c -o cmain。运行程序后,当给定 16 个或更多参数时,两者都失败了 - 不同之处在于,cmain只是发生了段错误,而main最终引发了“STORAGE_ERROR:堆栈溢出或错误的内存访问”。

由于 VLA 和无约束数组似乎(至少在表面上)都以类似的方式实现,并且前者被广泛认为在几乎所有情况下都不能安全使用,所以使用后者是否安全?

标签: cadavariable-length-array

解决方案


Ada 中的无约束数组类型本身并不是不安全的;不安全或至少可能导致异常的是使用未经检查的输入值(例如 Argument_Count)来创建该大小的数组对象。如果您这样做,并且没有异常处理程序,则攻击者可以使您的程序因未处理的异常而中止,如您的示例所示。

请注意,不受约束的数组类型在 Ada 中以两种方式使用:

  1. 如您的示例所示,创建动态确定大小的数组对象。
  2. 将各种大小的数组作为参数传递给子程序,即使实际的数组对象具有静态定义的大小。

第二种使用(参数)当然是完全安全的,参数的实际边界可以照常通过 A'First、A'Last、A'Range、A'Length 访问。


推荐阅读