电脑故障问答网

 找回密码
 立即注册
查看: 119|回复: 2

软件缺陷、错误与异常

[复制链接]

1

主题

4

帖子

4

积分

新手上路

Rank: 1

积分
4
发表于 2022-9-20 14:28:44 | 显示全部楼层 |阅读模式
本文不会对标题所述展开长篇大论,而是希望见微知著。
首先澄清编程的错误与异常模型的设计目标:错误与异常模型的目标是表达程序子例程的可枚举执行状态,可使调用方枚举程序状态并进行可靠处理,最终保证软件始终处于预期状态。
其次给出软件工程对bug的处理方法。在软件工程中,安全与可用性是两个不同级别的质量标准,由此可以将bug分为两类:如果一个bug的根因是不符合程序预期逻辑,则其是Semantic Bug;如果一个bug可以使系统蒙受安全影响,则其是Vulnerability。显然,随着软件复杂度的增加,潜在bug的数量会显著增加,所以最有效设计希望避免损失,而不是避免bug。从最大化收益角度,软件工程的目标是控制bug数量的灾难性增长:要求完全避免Vulnerability,从而保证用户安全;尽可能避免Semantic Bug,从而保证用户使用体验。
Weird Machine是程序安全分析的理论模型。初始时,程序处于一个clean state,此时整个系统工作于预期状态,可将系统的执行流程视为一个完成任务目标的图灵机 S 。当S接受预期的错误输入时,就进入到了错误处理例程,S可能输出一个程序失败 (Failure)或错误 (Error)。当S接受非预期的错误输入时,程序进入异常处理例程,S可能输出一个程序异常 (Exception)。如果程序错误地使用了程序资源或不能正常处理错误输入,那么此时程序所有可能的状态组成一个异常状态集合。其中Weird State是异常状态集合中时常令人关心的子集,其可能诱发程序被用户利用执行特定机器指令,造成安全影响。本文不过多介绍形式化的Weird Machine,而将利用Weird Machine的观点审视系统的错误和异常,并以操作系统中的文件系统为例。
文件系统具有高可用需求,所以其内部往往构建一套具有自我审查能力的机制,或称系统具备自省能力 (Introspection)。在系统运行期间,文件系统随时检查内部变量是否服从某种特征,进而判断系统当前是否处于Weird State,防止产生更大损失。许多文件系统在发现自身处于Weird State时,会主动削减自身的写入能力而仍然保留读取能力,期望保证系统可以借助外力恢复稳定。这种通过降低系统能力而保留部分能力的方式称为降级(Degradation),是具有高可用需求系统所需考虑的重要能力,主要防备了系统在Weird State中发生进一步不可预知的状态转移,因为根据前文观点,削弱系统能力将可能大幅降低系统数据被bug或异常输入进一步污染的危险性。
系统的可靠性源自对Weird State的发现能力,而系统的可用性源自对Weird State的修复能力与临近Weird State时对运行轨迹的控制能力。因为程序员始终在完成系统功能的同时孜孜不倦地增强系统的这些能力,因此编程语言的错误模型与其上的种种设计模式成为一种值得讨论的艺术。
最简单而高效的错误处理方法是让Routine返回错误的可枚举值,而自然而然的零返回值代表Routine的执行过程间没有错误。
enum Errno { OK, Err0, ErrY };
Errno computingRoutine(struct Out *ret, struct In * inp) { return {}; }
与之相似地,空值与非空值是常见的Routine返回值设计,进而可以认为这种范式通过约定正常返回值值域以外的魔术值作为Routine执行错误的警示。
int syscall::open() { return errno | fd; }
ssize_t syscall::read(int fd) { ssize_t bytesRead; return errno | bytesRead; }
template <typename T>
T* allocate() { return (new T) | nullptr; }
有的时候,正常返回值的值域是完整的,这个时候由tagged union演变的Union Result常常出现在编程语言中:
class Response<T> { code: 0; data: T }
class ErrorOutput { code: !0; message: string; }
function computingRoutine<T>(): Response<T> | ErrorOutput;或:
fn computingRoutine(): /* void => */ bool;
fn computingRoutine(): /* T => */ Option<T>;
fn computingRoutine(): /* T | E => */ Result<T, E>;
事实上,golang的错误模型也完全采纳了Union Result。golang通过编译期类型Tuple表达包括错误在内的多返回值类型。
func computingRoutine[T]() (T, error) {}对于程序无法容忍的异常,最简单的方法是使用语言中的panic机制。这时候Routine返回值类型只需考虑或表达为正常类型。
int computingRoutine(int a, int b) { return (b == 0 ? (throw std::runtime_error("FPE"), 0) : a / b); }
有的时候,程序设计者期望异常可以恢复,从而增强系统的可用性。结合longjump和rtti机制,C++实现了一套Exception机制,然而却饱受诟病。考虑改变C++的Exception设计,本文给出几个不同的思路。
与原始的Complete Panic相对的,一种被称为Isolated Panic的模式较少被显式提及。对于有gc的语言,一般可创建新的线程,并在进入线程前包装panic恢复所需的jumpbuf,而若执行中的Routine发生失败,便far jump到线程结束时完成Routine异常处理。对于无gc的语言,则需创建新的进程制造Isolated Panic,例如c++实现的chromium采取的多进程模型。
哪怕是Complete Panic,也常常转化为软件工程的重要技术,常常被人提及的是快速错误与灰度发布。赖以程序技术的迅速发展,以ASAN为代表的运行期检查器将Program Error直接转化为Complete Panic,让程序通过Panic直接从Weird State逃离,从而大大减少系统处于Weird State的机会。
回复

使用道具 举报

1

主题

4

帖子

7

积分

新手上路

Rank: 1

积分
7
发表于 2025-2-10 04:35:01 | 显示全部楼层
very good
回复

使用道具 举报

0

主题

5

帖子

7

积分

新手上路

Rank: 1

积分
7
发表于 2025-3-29 21:52:04 | 显示全部楼层
顶起顶起顶起
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

云顶设计嘉兴有限公司模板设计.

免责声明:本站上数据均为演示站数据,如购买模板可以上DISCUZ应用中心购买,欢迎惠顾.

云顶官方站点:云顶设计 模板原创设计:云顶模板   Powered by Discuz! X3.4© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表