【发布时间】:2013-09-30 18:34:19
【问题描述】:
我正在学习 D 编程语言,并且我试图将自己限制在我可以使用的 SafeD 子集。但是,我注意到像 writeln 这样的 I/O 函数都是@system。如何在 SafeD 中进行 I/O?
我在 Fedora 19 x86-64 上使用 LDC2(从 Fedora 软件包下载)。
【问题讨论】:
标签: d
我正在学习 D 编程语言,并且我试图将自己限制在我可以使用的 SafeD 子集。但是,我注意到像 writeln 这样的 I/O 函数都是@system。如何在 SafeD 中进行 I/O?
我在 Fedora 19 x86-64 上使用 LDC2(从 Fedora 软件包下载)。
【问题讨论】:
标签: d
你没有,或者至少没有直接。 I/O 需要进行系统调用,这意味着 C 函数,而 C 函数不会是 @safe。而且由于writeln 目前在后台调用printf,它肯定不会是@safe,因为用printf 做不安全的事情是微不足道的(比如给它@987654326 @ 然后传递一个整数而不是字符串)。在某些情况下可能可以创建writeln @trusted,但我不知道这会涉及什么。这将取决于它的实施方式。
任何重要的 D 程序都将使用@system 代码,这是完全可以预料的。诀窍是隔离它。你的程序的大部分希望是@safe,但它的部分必须是@system。但是,您只需检查程序的一小部分以确保内存安全。一旦您手动验证调用@system 函数的函数实际上是内存安全的,您可以将其标记为@trusted,然后您可以在@safe 代码中使用它。
不幸的是,druntime 和 Phobos 中的某些核心内容很可能是 @system,这取决于它对低级内容所做的事情,并且不一定所有这些内容都标有 @trusted,因为它应该是(例如,std.array.appender 可能是 @system,而它应该可以是 @trusted - 我不确定它目前是什么;它可能取决于数组的元素类型)。所以,很可能需要对一些标准库的东西进行一些改进,以便更好地支持@safe(正在进行中,但我不知道现在所有这些都在哪里),你可能会结束现在不得不在比将来更多的地方使用@trusted。 writeln 将来可能会也可能不会成为@safe 或@trusted。但是,如果您使用的类型没有 @safe 或 @trusted toString 函数,则绝对不会,所以writeln 是否是@safe 的一部分取决于你是什么使用它,不管它是如何实现的。但是,即使使用内置类型,它目前也不是 @safe 或 @trusted,所以现在,你运气不好。
如果你真的想要,你可以为 writeln 创建一个包装器 @trusted,但你必须非常小心以确保代码实际上是内存安全的 - 并且只需创建一个模板化的包装器并将其标记为@trusted 不会削减它,因为那样你就会将它视为@safe,无论你传递给它什么类型。因此,如果您确定 writeln 的特定用途是内存安全的,最好不要包装它,然后将调用者标记为 @trusted。当然,这也突出了为什么像 writeln 这样的函数首先是 @system 的部分原因:如果不信任不应信任的东西,通常很难编写 @trusted 模板代码(因为它取决于模板论据)。属性推断通常会解决这个问题,但如果模板化代码正在做一些需要@trusted 的事情,则很难将代码的一部分标记为@trusted 并将其余部分留给推断,尤其是在模板参数的情况下与@system 的东西混在一起。不过,我希望我们最终会解决所有标准库的问题。
【讨论】:
@system 代码,但它是孤立的,而且它通常是一个足够小的部分,可以自己验证它的内存安全性是合理的,而如果您根本没有@safe,则必须自己验证整个程序,这显然要困难得多。
writeln 可能是安全的,只要参数具有适当的@safe 功能(例如@safetoString),但它可以'不能简单地标记为@trusted 或@safe,而且我不知道在不标记不应该是@trusted 的部分@trusted 的情况下标记适当的部分@trusted 是多么容易。因此,根据实施情况,这可能会有点痛苦。我希望我们能到达那里。
我认为我们应该让 writeln 和朋友@trusted - 尽管他们使用低级原语,但他们会进行足够的检查以确保例如printf 没有收到混乱的参数。
【讨论】: