1e6c65d35SHu Haowen.. SPDX-License-Identifier: GPL-2.0 2e6c65d35SHu Haowen 3e6c65d35SHu Haowen.. include:: ../disclaimer-zh_CN.rst 4e6c65d35SHu Haowen 5e6c65d35SHu Haowen:Original: Documentation/dev-tools/testing-overview.rst 6*44a54e25SHu Haowen:Translator: 胡皓文 Hu Haowen <src.res.211@gmail.com> 7e6c65d35SHu Haowen 8e6c65d35SHu Haowen============ 9e6c65d35SHu Haowen内核测试指南 10e6c65d35SHu Haowen============ 11e6c65d35SHu Haowen 12e6c65d35SHu Haowen有许多不同的工具可以用于测试Linux内核,因此了解什么时候使用它们可能 13e6c65d35SHu Haowen很困难。本文档粗略概述了它们之间的区别,并阐释了它们是怎样糅合在一起 14e6c65d35SHu Haowen的。 15e6c65d35SHu Haowen 16e6c65d35SHu Haowen编写和运行测试 17e6c65d35SHu Haowen============== 18e6c65d35SHu Haowen 19e6c65d35SHu Haowen大多数内核测试都是用kselftest或KUnit框架之一编写的。它们都让运行测试 20e6c65d35SHu Haowen更加简化,并为编写新测试提供帮助。 21e6c65d35SHu Haowen 22e6c65d35SHu Haowen如果你想验证内核的行为——尤其是内核的特定部分——那你就要使用kUnit或 23e6c65d35SHu Haowenkselftest。 24e6c65d35SHu Haowen 25e6c65d35SHu HaowenKUnit和kselftest的区别 26e6c65d35SHu Haowen---------------------- 27e6c65d35SHu Haowen 28e6c65d35SHu Haowen.. note:: 29e6c65d35SHu Haowen 由于本文段中部分术语尚无较好的对应中文释义,可能导致与原文含义 30e6c65d35SHu Haowen 存在些许差异,因此建议读者结合原文 31e6c65d35SHu Haowen (Documentation/dev-tools/testing-overview.rst)辅助阅读。 32e6c65d35SHu Haowen 如对部分翻译有异议或有更好的翻译意见,欢迎联系译者进行修订。 33e6c65d35SHu Haowen 34e6c65d35SHu HaowenKUnit(Documentation/dev-tools/kunit/index.rst)是用于“白箱”测 35e6c65d35SHu Haowen试的一个完整的内核内部系统:因为测试代码是内核的一部分,所以它能够访 36e6c65d35SHu Haowen问用户空间不能访问到的内部结构和功能。 37e6c65d35SHu Haowen 38e6c65d35SHu Haowen因此,KUnit测试最好针对内核中较小的、自包含的部分,以便能够独立地测 39e6c65d35SHu Haowen试。“单元”测试的概念亦是如此。 40e6c65d35SHu Haowen 41e6c65d35SHu Haowen比如,一个KUnit测试可能测试一个单独的内核功能(甚至通过一个函数测试 42e6c65d35SHu Haowen一个单一的代码路径,例如一个错误处理案例),而不是整个地测试一个特性。 43e6c65d35SHu Haowen 44e6c65d35SHu Haowen这也使得KUnit测试构建和运行非常地快,从而能够作为开发流程的一部分被 45e6c65d35SHu Haowen频繁地运行。 46e6c65d35SHu Haowen 47e6c65d35SHu Haowen有关更详细的介绍,请参阅KUnit测试代码风格指南 48e6c65d35SHu HaowenDocumentation/dev-tools/kunit/style.rst 49e6c65d35SHu Haowen 50e6c65d35SHu Haowenkselftest(Documentation/dev-tools/kselftest.rst),相对来说,大量用 51e6c65d35SHu Haowen于用户空间,并且通常测试用户空间的脚本或程序。 52e6c65d35SHu Haowen 53e6c65d35SHu Haowen这使得编写复杂的测试,或者需要操作更多全局系统状态的测试更加容易(诸 54e6c65d35SHu Haowen如生成进程之类)。然而,从kselftest直接调用内核函数是不行的。这也就 55e6c65d35SHu Haowen意味着只有通过某种方式(如系统调用、驱动设备、文件系统等)导出到了用 56e6c65d35SHu Haowen户空间的内核功能才能使用kselftest来测试。为此,有些测试包含了一个伴 57e6c65d35SHu Haowen生的内核模块用于导出更多的信息和功能。不过,对于基本上或者完全在内核 58e6c65d35SHu Haowen中运行的测试,KUnit可能是更佳工具。 59e6c65d35SHu Haowen 60e6c65d35SHu Haowenkselftest也因此非常适合于全部功能的测试,因为这些功能会将接口暴露到 61e6c65d35SHu Haowen用户空间,从而能够被测试,而不是展现实现细节。“system”测试和 62e6c65d35SHu Haowen“end-to-end”测试亦是如此。 63e6c65d35SHu Haowen 64e6c65d35SHu Haowen比如,一个新的系统调用应该伴随有新的kselftest测试。 65e6c65d35SHu Haowen 66e6c65d35SHu Haowen代码覆盖率工具 67e6c65d35SHu Haowen============== 68e6c65d35SHu Haowen 69e6c65d35SHu Haowen支持两种不同代码之间的覆盖率测量工具。它们可以用来验证一项测试执行的 70e6c65d35SHu Haowen确切函数或代码行。这有助于决定内核被测试了多少,或用来查找合适的测试 71e6c65d35SHu Haowen中没有覆盖到的极端情况。 72e6c65d35SHu Haowen 730a03801cSHu HaowenDocumentation/translations/zh_CN/dev-tools/gcov.rst 是GCC的覆盖率测试 740a03801cSHu Haowen工具,能用于获取内核的全局或每个模块的覆盖率。与KCOV不同的是,这个工具 750a03801cSHu Haowen不记录每个任务的覆盖率。覆盖率数据可以通过debugfs读取,并通过常规的 760a03801cSHu Haowengcov工具进行解释。 77e6c65d35SHu Haowen 780a03801cSHu HaowenDocumentation/dev-tools/kcov.rst 是能够构建在内核之中,用于在每个任务 790a03801cSHu Haowen的层面捕捉覆盖率的一个功能。因此,它对于模糊测试和关于代码执行期间信 800a03801cSHu Haowen息的其它情况非常有用,比如在一个单一系统调用里使用它就很有用。 81e6c65d35SHu Haowen 82e6c65d35SHu Haowen动态分析工具 83e6c65d35SHu Haowen============ 84e6c65d35SHu Haowen 85e6c65d35SHu Haowen内核也支持许多动态分析工具,用以检测正在运行的内核中出现的多种类型的 86e6c65d35SHu Haowen问题。这些工具通常每个去寻找一类不同的缺陷,比如非法内存访问,数据竞 87e6c65d35SHu Haowen争等并发问题,或整型溢出等其他未定义行为。 88e6c65d35SHu Haowen 89e6c65d35SHu Haowen如下所示: 90e6c65d35SHu Haowen 91e6c65d35SHu Haowen* kmemleak检测可能的内存泄漏。参阅 92e6c65d35SHu Haowen Documentation/dev-tools/kmemleak.rst 93e6c65d35SHu Haowen* KASAN检测非法内存访问,如数组越界和释放后重用(UAF)。参阅 94e6c65d35SHu Haowen Documentation/dev-tools/kasan.rst 95e6c65d35SHu Haowen* UBSAN检测C标准中未定义的行为,如整型溢出。参阅 96e6c65d35SHu Haowen Documentation/dev-tools/ubsan.rst 97e6c65d35SHu Haowen* KCSAN检测数据竞争。参阅 Documentation/dev-tools/kcsan.rst 98e6c65d35SHu Haowen* KFENCE是一个低开销的内存问题检测器,比KASAN更快且能被用于批量构建。 99e6c65d35SHu Haowen 参阅 Documentation/dev-tools/kfence.rst 100e6c65d35SHu Haowen* lockdep是一个锁定正确性检测器。参阅 101e6c65d35SHu Haowen Documentation/locking/lockdep-design.rst 102e6c65d35SHu Haowen* 除此以外,在内核中还有一些其它的调试工具,大多数能在 103e6c65d35SHu Haowen lib/Kconfig.debug 中找到。 104e6c65d35SHu Haowen 105e6c65d35SHu Haowen这些工具倾向于对内核进行整体测试,并且不像kselftest和KUnit一样“传递”。 106e6c65d35SHu Haowen它们可以通过在启用这些工具时运行内核测试以与kselftest或KUnit结合起来: 107e6c65d35SHu Haowen之后你就能确保这些错误在测试过程中都不会发生了。 108e6c65d35SHu Haowen 109e6c65d35SHu Haowen一些工具与KUnit和kselftest集成,并且在检测到问题时会自动打断测试。 11063c1d251SYanteng Si 11163c1d251SYanteng Si静态分析工具 11263c1d251SYanteng Si============ 11363c1d251SYanteng Si 11463c1d251SYanteng Si除了测试运行中的内核,我们还可以使用**静态分析**工具直接分析内核的源代 11563c1d251SYanteng Si码(**在编译时**)。内核中常用的工具允许人们检查整个源代码树或其中的特 11663c1d251SYanteng Si定文件。它们使得在开发过程中更容易发现和修复问题。 11763c1d251SYanteng Si 11863c1d251SYanteng Si Sparse可以通过执行类型检查、锁检查、值范围检查来帮助测试内核,此外还 11963c1d251SYanteng Si 可以在检查代码时报告各种错误和警告。关于如何使用它的细节,请参阅 12063c1d251SYanteng Si Documentation/translations/zh_CN/dev-tools/sparse.rst。 12163c1d251SYanteng Si 12263c1d251SYanteng Si Smatch扩展了Sparse,并提供了对编程逻辑错误的额外检查,如开关语句中 12363c1d251SYanteng Si 缺少断点,错误检查中未使用的返回值,忘记在错误路径的返回中设置错误代 12463c1d251SYanteng Si 码等。Smatch也有针对更严重问题的测试,如整数溢出、空指针解除引用和内 12563c1d251SYanteng Si 存泄漏。见项目页面http://smatch.sourceforge.net/。 12663c1d251SYanteng Si 12763c1d251SYanteng Si Coccinelle是我们可以使用的另一个静态分析器。Coccinelle经常被用来 12863c1d251SYanteng Si 帮助源代码的重构和并行演化,但它也可以帮助避免常见代码模式中出现的某 12963c1d251SYanteng Si 些错误。可用的测试类型包括API测试、内核迭代器的正确使用测试、自由操 13063c1d251SYanteng Si 作的合理性检查、锁定行为的分析,以及已知的有助于保持内核使用一致性的 13163c1d251SYanteng Si 进一步测试。详情请见Documentation/dev-tools/coccinelle.rst。 13263c1d251SYanteng Si 13363c1d251SYanteng Si 不过要注意的是,静态分析工具存在**假阳性**的问题。在试图修复错误和警 13463c1d251SYanteng Si 告之前,需要仔细评估它们。 135e07e9f22SYanteng Si 136e07e9f22SYanteng Si何时使用Sparse和Smatch 137e07e9f22SYanteng Si---------------------- 138e07e9f22SYanteng Si 139e07e9f22SYanteng SiSparse做类型检查,例如验证注释的变量不会导致无符号的错误,检测 140e07e9f22SYanteng Si``__user`` 指针使用不当的地方,以及分析符号初始化器的兼容性。 141e07e9f22SYanteng Si 142e07e9f22SYanteng SiSmatch进行流程分析,如果允许建立函数数据库,它还会进行跨函数分析。 143e07e9f22SYanteng SiSmatch试图回答一些问题,比如这个缓冲区是在哪里分配的?它有多大?这 144e07e9f22SYanteng Si个索引可以由用户控制吗?这个变量比那个变量大吗? 145e07e9f22SYanteng Si 146e07e9f22SYanteng Si一般来说,在Smatch中写检查比在Sparse中写检查要容易。尽管如此, 147e07e9f22SYanteng SiSparse和Smatch的检查还是有一些重叠的地方。 148e07e9f22SYanteng Si 149e07e9f22SYanteng SiSmatch和Coccinelle的强项 150e07e9f22SYanteng Si------------------------ 151e07e9f22SYanteng Si 152e07e9f22SYanteng SiCoccinelle可能是最容易写检查的。它在预处理器之前工作,所以用Coccinelle 153e07e9f22SYanteng Si检查宏中的错误更容易。Coccinelle还能为你创建补丁,这是其他工具无法做到的。 154e07e9f22SYanteng Si 155e07e9f22SYanteng Si例如,用Coccinelle你可以从 ``kmalloc_array(x, size, GFP_KERNEL)`` 156e07e9f22SYanteng Si到 ``kmalloc_array(x, size, GFP_KERNEL)`` 进行大规模转换,这真的很 157e07e9f22SYanteng Si有用。如果你只是创建一个Smatch警告,并试图把转换的工作推给维护者,他们会很 158e07e9f22SYanteng Si恼火。你将不得不为每个警告争论是否真的可以溢出。 159e07e9f22SYanteng Si 160e07e9f22SYanteng SiCoccinelle不对变量值进行分析,而这正是Smatch的强项。另一方面,Coccinelle 161e07e9f22SYanteng Si允许你用简单的方法做简单的事情。 162