unrestricted_access的安全性

时间:2014-07-23 22:00:56

标签: ada

我的情况很复杂,所以我希望能够妥善解释。

我将unchecked_access与Ada.Finalization.Controlled类型结合使用,将对vector的引用传递给Initialize过程中超出范围的受保护哈希映射类型,并在finalize过程中删除受保护映射中的引用。这样我认为我可以确保任何任务都不可能看到地图中的范围引用。

然而,我使用受保护地图组织快照的方式是在它使用的每个实例(有效地使它成为普通的hashed_map)中拍摄的,在使用它的过程中,矢量引用可能超出范围和快照镜头仍会有参考并尝试访问它。

我可以看到这会产生2个问题,要么我正在创建悬空指针并试图引用释放的内存,要么我的引用快照保持内存存活并且我要留下垃圾。我做了一个测试,看看会发生什么,看起来内存仍然存在,但这是真的吗?我的组织还有其他问题吗?

with Ada.Containers; use Ada.Containers;
with Ada.Containers.Vectors;
with Ada.Text_IO; use Ada.Text_IO;
procedure Test is
  package V_Integer is new Ada.Containers.Vectors(Positive, Integer);
  use V_Integer;
  type V_Access is access all Vector;
  Bar : V_Access;
begin
  declare
  Foo : aliased Vector;
  begin
    Bar := Foo'unrestricted_Access;
    Foo.Append(3);
    Foo.Append(5);
    Put_Line("In scope: " & count_type'image(Length(Bar.all)));
  end;
  -- Will this reference always exist? Does it need to be freed?
  Put_Line("Out of scope: " & count_type'image(Length(Bar.all))); 
end Test;

1 个答案:

答案 0 :(得分:2)

begin
  declare
  Foo : aliased Vector;
  begin
    Bar := Foo'unrestricted_Access;
    Foo.Append(3);
    Foo.Append(5);
    Put_Line("In scope: " & count_type'image(Length(Bar.all)));
  end;
  -- Will this reference always exist? Does it need to be freed?
  Put_Line("Out of scope: " & count_type'image(Length(Bar.all))); 
end Test;

Foo将是Vector类型的对象,它可能存在于堆栈中。这个对象本身就是一个相对较小的记录,在GNAT中可能大约有6个32位的单词(给出或拿走一些,我还没有检查过)。它包含一个访问组件,用于获取所有向量的元素,并包含一些其他内务处理信息。 Bar将指向那个小的6个字的记录。基本上它将包含堆栈中某些东西的地址。

由于堆栈上存在小记录Foo,当它超出范围时,堆栈空间可用于其他内容。在这种情况下是否会发生,我不知道。但是如果在示例中的块后面有另一个declare...begin...end块,则新块使用的局部变量可以重用相同的堆栈空间。或者如果调用了一个过程,那么会在堆栈中放入不同的东西。在任何一种情况下,Foo以前使用的堆栈空间都将被覆盖。并且Bar仍将指向相同的地址,但它指向的区域将被其他数据覆盖。所以结果可能是错误的,可能是一场灾难。

我不知道这究竟是如何实现的,但无论它是如何实现的,这段代码都可能是灾难性的。要记住的主要事项是:(1)如果变量超出范围,则可以随意重用用于该变量的空间; (2)如果你使用'Unchecked_Access(或'Unrestricted_Access)来设置指向该变量的指针,那么在变量超出范围之后,访问指针所指向的数据可能会让你变得垃圾或非常不良行为; (3)变量,无论是否有别名,都不会(通常)动态分配,并且程序不需要(也不能)明确地释放它们,即使您已使用'Unchecked_Access创建了对它们的引用