【问题标题】:Deep copy of function arguments for polymorphic types多态类型的函数参数的深层副本
【发布时间】:2020-11-06 02:56:13
【问题描述】:

我使用一个基于基本包的对象,大致定义为:

package Base is 
   type T_Base is abstract tagged null record;

   -- This performs a deep copy. Shallow copies may lead to STORAGE_ERROR.
   -- This shall be implemented by every derived type.
   function Copy (From : in T_Base) return T_Base'Class is abstract;
end package Base;

这个包是由几个包派生而来的,这些包进一步派生出来

package Foo is
   type T_Foo is new T_Base with record
      A_Data : Natural;  -- Of course, in the real code, these are types by far more complex.
   end record;

   procedure do_something (Foo_Object : in T_Foo);
   -- This implements the deep copy
   function Copy (From : in T_Foo) return T_Base'Class is abstract;
end package Foo;

在调用过程do_something 时,我确实得到了storage_error

procedure handle_received_foo (Foo_In: in Foo.T_Foo) is
begin
   Foo.do_something (Foo_Object => Foo_In); -- The storage error does happen here.
end main;

使用 gdb 运行代码时,输​​入函数时出现段错误,我得到:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 39 (LWP 39)]
0x033c9828 in foo.do_something (foo_object=...) at ./foo.adb:67
67         procedure do_something (Foo_Object : in T_Foo);
(gdb) p foo_object
$1 (null)

所以我想我在对参数Foo_Object 进行浅表复制时会得到一个storage_error

我知道这不是 MWE,并且派生类型中使用的其中一种类型可能存在错误。

我找不到任何好的选择:

  • 如果不大幅更改其定义,我无法从T_BaseAda.Finalization.Controlled 中派生T_Foo,因此将T_Foo 设为Controlled 类型以在Adjust 中调用Copy 似乎是不可能的。它们都不是接口类型

  • T_Base 定义为

    type T_Base is abstract new Ada.Finalization.Controlled with null record;
    

    并在此处覆盖 Adjust 似乎会导致对现有代码库的大量修改,因为 gnat 在多个地方产生了

    聚合类型具有私有祖先“受控”必须使用扩展聚合。

所以我缺乏进一步调查问题或用锤子解决问题的解决方案。

【问题讨论】:

  • 如何将 T_FOO 传递给主程序?如果 main 有一个本地声明并正确初始化的 T_FOO,do_something 调用是否有效?
  • 我通过网络获得了 T_FOO。它确实不在我的主程序中(对不起,应该没有调用这个主程序)。 T_Foo 比示例中的复杂得多。但我想我可以比较这种类型的深拷贝和浅拷贝,看看它们是否会产生存储错误。
  • 我没有看到对 Copy 的任何呼叫。就目前而言,您似乎将null 传递给Foo.Do_Something - 不知道这是怎么发生的
  • 我可能完全走错了路。对代码进行一些研究以研究副本移动了 storage_error。我正在考虑源于 storage_size 太小的问题,per the doc“对于任务,Storage_Size 子句指定要为任务堆栈分配的空间量。这不能扩展,如果堆栈耗尽,则 Storage_Error将被引发(如果启用堆栈检查)。“在我的情况下,启用了“-fstack-check”......

标签: ada


【解决方案1】:

问题不在于Copy 函数。我在代码库中看到的 cmets 具有误导性。

引入新变量改变了异常位置的事实让我考虑了一些堆栈溢出问题。

确实为该任务分配的Storage_Size 是不够的。增加pragma Storage_Size(<value>) 解决了这个问题。

由于代码库是用-fstack-check编译的,这就导致了前面提到的STORAGE_ERROR

更多信息on Adacore's documentation.

Gem #95: Dynamic Stack Analysis in GNAT 可能已经看到了这一点,但我目前无法看到其中建议的绑定选项的任何结果。

【讨论】:

  • 如果您没有使用-fstack-check,而不是Storage_Error,您可能迟早会看到来自操作系统的段错误。我最糟糕的记忆是跟踪导致其中任何一个的错误......
  • 我同意由于-fstack-check 而“更早”地看到错误使调试更容易。但是,由于无法使用 -u binder 选项检查堆栈要求,而 gdb 使用 info tasks 告诉我我有大约 50 个任务正在运行并且对其中任何一个任务都没有信心,这让我毛骨悚然......跨度>
猜你喜欢
  • 2012-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多