- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
根据Spark2014文档,Spark代码中不允许处理异常。
通过验证,可以排除大多数运行时错误发生在编写的程序中,但无法排除像 Storage_Error
这样的异常。
由于 Storage_Error
可能发生在每个过程/函数调用上或使用 new
动态分配内存时(如果我错了,请纠正我),捕获并处理Spark_Mode=off 的代码段中的此异常仅在程序的最高级别(程序的入口点)有效。我真的不喜欢这种方法,因为您几乎失去了对此类异常使用react的所有可能性。
我想做的事情:
假设使用过程Add()
创建一棵无界树。在此过程中,我想检查堆上是否有足够的空间,以在树内创建一个新节点。如果存在,则为该节点分配内存并将其添加到树中,否则可以给出一个输出参数,其中设置某种标志。
我已经搜索了 Spark UserGuide,但无法找到一种处理方法,只是程序员必须确保有足够的可用内存,但不知道如何做到这一点。
如何在 Spark 中处理此类异常?
最佳答案
SPARK 确实无法证明(保证)不存在存储错误,因为这些错误是从程序范围之外引发的。对于失败的堆分配以及堆栈空间耗尽时都是如此。
但是,可以通过从 SPARK 分析中避免分配例程来进行一点欺骗,如下例所示。分配子程序 New_Integer
具有 SPARK 可以用来分析指针的后置条件,但子程序的主体不进行分析。这允许处理 Storage_Error
。当然,现在必须注意主体确实符合规范:当 Valid
为 true 时,Ptr
字段不得为 null
。 SPARK 现在只假设这是真的,但不会验证这一点。
注意:所有指针取消引用和不存在内存泄漏都可以使用 GNAT CE 2021 来证明。但是,最好将 Valid
鉴别器实际设置为 False
在 Free
期间使用后置条件,例如 Post => P.Valid = False
。不幸的是,这使得 SPARK 提示可能的判别检查失败。
更新(2021 年 6 月 3 日)
我根据@YannickMoy 的提示更新了示例(见下文)。 Free
现在可确保弱指针的 Valid
鉴别器在返回时设置为 False
。
main.adb
with Test;
procedure Main with SPARK_Mode is
X : Test.Weak_Int_Ptr := Test.New_Integer (42);
Y : Integer;
begin
-- Dereference.
if X.Valid then
Y := X.Ptr.all;
end if;
-- Free.
Test.Free (X);
end Main;
测试.ads
package Test with SPARK_Mode is
type Int_Ptr is access Integer;
-- A weak pointer that may or may not be valid, depending on
-- on whether the allocation succeeded.
type Weak_Int_Ptr (Valid : Boolean := False) is record
case Valid is
when False => null;
when True => Ptr : Int_Ptr;
end case;
end record;
function New_Integer (N : Integer) return Weak_Int_Ptr
with Post => (if New_Integer'Result.Valid then New_Integer'Result.Ptr /= null);
-- Allocates a new integer.
procedure Free (P : in out Weak_Int_Ptr)
with
Pre => not P'Constrained,
Post => P.Valid = False;
-- Deallocates an integer if needed.
end Test;
测试.adb
with Ada.Unchecked_Deallocation;
package body Test with SPARK_Mode is
-----------------
-- New_Integer --
-----------------
function New_Integer (N : Integer) return Weak_Int_Ptr is
pragma SPARK_Mode (Off); -- Refrain body from analysis.
begin
return Weak_Int_Ptr'(Valid => True, Ptr => new Integer'(N));
exception
when Storage_Error =>
return Weak_Int_Ptr'(Valid => False);
end New_Integer;
----------
-- Free --
----------
procedure Free (P : in out Weak_Int_Ptr) is
procedure Local_Free is new Ada.Unchecked_Deallocation
(Object => Integer, Name => Int_Ptr);
begin
if P.Valid then
Local_Free (P.Ptr);
P := Weak_Int_Ptr'(Valid => False);
end if;
end Free;
end Test;
输出 (gnatprove)
$ gnatprove -Pdefault.gpr -j0 --level=0 --report=all
Phase 1 of 2: generation of Global contracts ...
Phase 2 of 2: flow analysis and proof ...
main.adb:5:04: info: absence of memory leak at end of scope proved
main.adb:13:13: info: discriminant check proved
main.adb:13:18: info: pointer dereference check proved
main.adb:17:08: info: precondition proved
test.adb:31:23: info: discriminant check proved
test.adb:32:12: info: discriminant check proved
test.adb:32:12: info: absence of memory leak proved
test.ads:22:16: info: postcondition proved
Summary logged in [...]/gnatprove.out
摘要(由OP添加)
提供的代码有助于防止使用 new
关键字动态分配Storage_Error
。由于 SPARK 已经证明了无限递归(如评论中所述。请参阅 here ),唯一可能导致 Storage_Error
的开放问题是程序在正常情况下需要更多堆栈执行比可用的执行要多。然而,这可以通过 GNATstack 等工具在编译时进行监控和确定(也在评论中提到。请参阅 here )。
关于ada - 如何检查 Spark_Ada 中的 Storage_Error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67806008/
如何在过程中编写迭代器?对不起我的转储问题,我是新手。感谢您的回答。 最佳答案 这完全取决于您需要迭代的内容。 数组?使用loop : plain, for, or while. predefined
我现在知道很多编程语言。回到我 18 岁的时候,我几乎加入了美国空军,并且对 Ada 进行了测试。那是十多年前的事了。 Ada 编程语言在军队中是否仍然像以前一样重要? 我想知道新的军事软件项目是否仍
在 Java 或 C# 中,您经常会拥有 final 的类成员。或 readonly - 它们设置一次,然后再也不碰。它们可以为类的不同实例保存不同的值。 艾达有没有类似的东西?我试图在 Ada 中创
即使使用这个简单的示例,我也无法让动态调度正常工作。我相信问题在于我如何设置类型和方法,但看不到在哪里! with Ada.Text_Io; procedure Simple is type A
我目前正在自学 Ada,尽管我可以从解决一些更传统的问题开始。 更具体地说,我尝试计算阶乘 n!,而 n>100。到目前为止,我的实现是: with Ada.Text_IO; with Ada.Int
目前正在学习 Ada 并真正享受它,有一件事情困扰着我:什么是 tagged类型?根据 John Barnes 的 Programming in Ada 2012,它表示实例化的对象在运行时带有标签。
你好 我正在尝试我在 Ada 中创建单人骰子游戏的第一个程序。 但面临着保持球员得分的问题。 目标:每个玩家有 10 个回合,如果 2 次掷骰总数为 7,则获得 10 分 问题:每次总分被重置并且 1
您可以通过让函数返回一个值来分配给变量: My_Int : Integer := My_Math_Func [(optional params)]; 或者你可以用一个过程来做到这一点(假设 My_In
我试图在 Ada 中将字符转换为整数,似乎没有任何效果,到目前为止我已经能够从 ASCII 返回 DEC,但我想返回 0(整数)。 Character'Pos('0'); 返回 48 --我希望它返回
假设我有以下常量来定义一个只接受其范围定义内的有效值的子类型: type Unsigned_4_T is mod 2**4; valid_1 : constant Unsigned_4_T :=
我正在尝试创建一个 tree-sitter解析器,以便 IDE(在本例中为 Vim)可以解析 Ada 程序文本并进行更高级的操作,例如 extract-subprogram 和 rename-vari
我正在写一篇关于 Ada 83 的论文。我们有一个作业,列出了论文的各个部分(历史、设计目标、语法等)。讲师提到我们中的一些人将有一些部分简单地说“此语言不支持此功能。” 其中两个部分是数据类型和
假设我有以下常量来定义一个只接受其范围定义内的有效值的子类型: type Unsigned_4_T is mod 2**4; valid_1 : constant Unsigned_4_T :=
我正在尝试创建一个 tree-sitter解析器,以便 IDE(在本例中为 Vim)可以解析 Ada 程序文本并进行更高级的操作,例如 extract-subprogram 和 rename-vari
我想声明一个元素类型为变体记录的数组。像这样: type myStruct (theType : vehicleType) is record ... when car => numOfWheels
我正在实例化一个带有枚举的通用包,以访问多个值之一并在子程序重载中使用。我想要一组定义明确、编译时检查过的值,我可以使用和查找。 generic -- Different types beca
我有以下包: ------------------- -- File: father.ads ------------------- package Father with SPARK_Mode =>
对于最后的程序,我从 gnat 收到以下错误消息: test2.adb:23:61: error: invalid operand types for operator "-" test2.adb:2
我编写了一个加密文件的 Ada 程序。它逐 block 读取它们以节省目标机器上的内存。不幸的是,Ada 的目录库读取 Long_Integer 中的文件大小,将读取限制为近 2GB 文件。尝试读取超
我想打印访问变量(指针)的地址以进行调试。 type Node is private; type Node_Ptr is access Node; procedure foo(n: in out No
我是一名优秀的程序员,十分优秀!