12

我正在编写一个以 FILE * 指针作为输入的小型库。

如果我立即检查这个 FILE * 指针并发现它导致了段错误,那么处理信号、设置 errno 并优雅退出是否更正确;或者什么都不做并使用调用者安装的信号处理程序,如果他有一个?

流行的智慧似乎是“图书馆永远不应该导致崩溃”。但我的想法是,既然这个特定的信号肯定是调用者的错,那么我不应该试图向他隐藏那个信息。他可能安装了自己的处理程序,以自己的方式对问题做出反应。可以使用 errno 检索相同的信息,但设置 SIGSEGV 的默认配置是有充分理由的,并且通过强制调用者处理他的错误,或通过崩溃和保护他免受进一步损害,向上传递信号尊重这一理念.

您是否同意这种分析,或者您认为在这种情况下处理 SIGSEGV 有什么令人信服的理由?

4

6 回答 6

7

接管处理程序不是图书馆业务,除非明确要求,否则我会说这对他们有些冒犯。为了最大限度地减少崩溃,库可能会在一定程度上验证他们的输入。除此之外:垃圾进——垃圾出。

于 2012-01-23T19:54:28.973 回答
5

流行的智慧似乎是“图书馆永远不应该导致崩溃”。

我不知道你从哪里得到的——如果他们传递了一个无效的指针,你应该崩溃。任何图书馆都会。

于 2012-01-23T19:52:21.747 回答
3

我认为检查NULL指针的特殊情况是合理的。但除此之外,如果他们通过垃圾,他们就违反了函数的合同,他们会崩溃。

于 2012-01-23T19:57:42.267 回答
2

这是一个主观问题,可能不适合 SO,但我会提出我的意见:

这样想:如果你有一个函数接受一个以 nul 结尾的char *字符串并且被记录为这样,并且调用者传递了一个没有 nul 终止符的字符串,你是否应该捕捉到信号并将调用者拍在手腕上?还是应该让它崩溃并让糟糕的程序员使用你的 API 修复他/她的代码?

如果您的代码带有一个FILE *指针,并且您的文档说“通过任何打开FILE *”,并且它们传递了一个关闭或无效的FILE *对象,那么它们就违反了合同。检查这种情况会减慢正确使用您的库的人的代码以适应不使用您的库的人,而让它崩溃将使阅读文档并编写好的代码的人尽可能快地保持代码。

您是否期望传递无效FILE *指针的人检查并正确处理错误?还是他们更有可能盲目地继续,稍后导致另一个崩溃,在这种情况下处理这个崩溃可能只是掩饰错误?

于 2012-01-23T19:55:30.870 回答
1

如果你给它们一个错误的指针,内核不应该崩溃,但库可能应该。这并不意味着您不应该进行错误检查。一个好的程序在遇到不合理的坏数据时会立即死亡。我宁愿使用 assert(f != NULL) 调用 bail 库,而不是仅仅滚动并最终取消引用 NULL 指针。

于 2012-01-23T19:59:22.907 回答
0

抱歉,那些说库应该崩溃的人只是懒惰(也许是考虑到时间,以及开发工作)。库是函数的集合。库代码不应该“只是崩溃”,就像软件中的其他功能应该“只是崩溃”一样。

诚然,如果通常涉及多种语言或(相对)外来语言功能(如异常),库可能在如何跨 API 边界传递错误方面存在一些问题,但这并没有什么特别之处。实际上,这只是编写库的一部分负担,而不是应用程序内的代码。

除非您确实无法证明开销是合理的,否则系统之间的每个接口都应实施健全性检查,或者更好的是,按合同设计,以防止安全问题和错误。

有很多方法可以解决这个问题,您可能应该按照优先顺序执行以下操作之一:

  1. 在库中使用支持异常(或者更好的是,按合同设计)的语言,并在合同上抛出异常或允许合同失败。

  2. 提供错误处理信号/槽或钩子/回调机制,并调用任何已注册的处理程序。要求在初始化库时,至少注册一个错误处理程序。

  3. 支持在每个可能因任何原因而失败的函数中返回一些错误代码。但这是从 C(相对于 C++)时代开始的旧的、相对疯狂的做事方式。

  4. Set some global "an error has occurred flag", and allow clearing that flag before calls. This is also old, and completely insane, mostly because it moves error status maintence burden to the caller, AND is unsafe when it comes to threading.

于 2013-02-22T22:20:04.673 回答