FreeRTOS TaskSuspendAll 内存安全证明解析:基于 CBMC 的零假设形式化验证实战

FreeRTOS TaskSuspendAll 内存安全证明解析:基于 CBMC 的零假设形式化验证实战 FreeRTOS TaskSuspendAll 内存安全证明解析基于 CBMC 的零假设形式化验证实战【免费下载链接】FreeRTOSClassic FreeRTOS distribution. Started as Git clone of FreeRTOS SourceForge SVN repo. Submodules the kernel.项目地址: https://gitcode.com/GitHub_Trending/fr/FreeRTOS导读本文以 FreeRTOS 官方仓库中FreeRTOS/Test/CBMC/proofs/Task/TaskSuspendAll/这一 CBMCC Bounded Model Checker形式化验证证明为对象深入剖析 FreeRTOS 内核任务调度接口vTaskSuspendAll()的内存安全证明是如何组织、构建与运行的。读完本文你将理解一个零假设、零抽象的 CBMC 证明从 harness 编写、Makefile 配置到缺函数声明的完整套路并能对照TaskResumeAll等兄弟证明掌握如何用同样的方法为自己的内核接口编写内存安全证明。证明目标验证 vTaskSuspendAll 的内存安全性在 FreeRTOS 中vTaskSuspendAll()是任务级临界区的入口——它通过挂起调度器scheduler suspension来禁止任务切换从而在不关闭中断的前提下保护临界区代码不被其他任务抢占。由于它被大量内核内部路径队列、信号量、事件组等广泛调用其内存安全直接关系到整个内核的可靠性。本证明的官方 READMETaskSuspendAll/README.md开宗明义地说明了验证目标与难度This proof demonstrates the memory safety of the TaskSuspendAll function. No assumption or abstraction is required for this memory-safety proof.也就是说这个证明要展示vTaskSuspendAll()函数体在执行过程中不会产生越界读写、空指针解引用、释放后使用等内存错误并且不需要任何前提假设也不需要任何函数抽象——这是所有 CBMC 证明中最理想、也最干净的一种形态。同时 README 也诚实标注了该证明的状态This proof is a work-in-progress. Proof assumptions are described in the harness.即证明仍处于进行中状态所有与假设相关的细节都以注释形式记录在 harness 文件中。极简 Harness直接调用无任何前置条件整个证明的核心入口是 harness 文件 TaskSuspendAll_harness.c。与大多数需要初始化任务列表、设置全局变量的证明不同这个 harness 短到只有一次函数调用#include stdint.h /* FreeRTOS includes. */ #include FreeRTOS.h #include task.h /* * We just call vTaskSuspendAll(). No assumption * or abstraction is required for this proof */ void harness() { vTaskSuspendAll(); }关键信息如下零假设harness 中没有任何__CPROVER_assume调用也没有对全局变量做非确定性赋值nondeterministic assignment零抽象注释明确写道 No assumption or abstraction is required不需要假设或抽象即证明直接对vTaskSuspendAll()的真实内核实现进行符号执行而不是用桩函数替代无返回值检查vTaskSuspendAll()返回void因此 harness 只需执行调用即可完成一次完整的符号路径探索。这种极简形态成立的深层原因是vTaskSuspendAll()不带参数、返回空、且其行为只涉及对内核全局变量如调度器挂起计数的简单读写不触碰链表遍历或复杂数据结构——因此在 CBMC 的有限展开下不需要任何额外的状态准备。从 Makefile 的OBJS项也能印证证明实际链接的只有内核任务模块与链表模块的 goto 程序OBJS: [ $(ENTRY)_harness.goto, $(FREERTOS)/Source/tasks.goto, $(FREERTOS)/Source/list.goto ]即该证明对tasks.c任务调度内核与list.c就绪/阻塞链表实现的真实代码做内存安全验证而不是验证某个替身实现。Makefile.json 剖析一份证明的构建蓝图CBMC 证明体系采用 Python 构建脚本 JSON 配置的方式描述每个证明。本证明的 Makefile.json 完整定义了构建参数逐项解读如下字段值含义ENTRYTaskSuspendAll证明的入口名同时用于生成_harness.goto等产物文件名DEFmtCOVERAGE_TEST_MARKER()__CPROVER_assert(1, Coverage marker)用宏定义把覆盖测试标记替换为 CBMC 断言恒真断言保证覆盖率打点不会成为误报来源CBMCFLAGS--unwind 1指示 CBMC 将循环展开 1 次。由于该证明无需深循环单次展开即可覆盖全部路径OBJSTaskSuspendAll_harness.goto、Source/tasks.goto、Source/list.goto参与验证的目标文件harness 本身 内核任务模块 链表模块INC$(FREERTOS)/Test/CBMC/proofs/Task/TaskSuspendAll/附加头文件搜索路径指向证明所在目录这里的.goto文件是 CBMC 工具链的中间产物先用goto-cc或goto-cl把 C 源码编译成带控制流图CFG的 goto 程序再由cbmc对这些 goto 程序做符号执行与 SAT/SMT 求解。--unwind 1直接反映了本证明结构简单、路径浅的特性——对比之下TaskResumeAll的证明因为涉及xPendedTicks的循环处理其配置就需要对循环展开次数做更精细的权衡详见下文对比章节。expected-missing-functions允许缺失的函数集合一份证明里被调用的函数不可能全部来自链接的目标文件。FreeRTOS 内核与具体移植层port layer解耦tasks.c中调用vPortEnterCritical、xPortStartScheduler等函数只以声明形式存在具体实现由各硬件移植目录提供。CBMC 在做符号执行时会遇到这些未定义函数处理方式有两种要么提供桩stub要么声明为expected missing允许缺失。本证明的 cbmc-viewer.json 通过expected-missing-functions字段显式列出了 20 个允许缺失的函数可归为几类移植层port layer函数pxPortInitialiseStack、vPortCloseRunningThread、vPortDeleteThread、vPortEnterCritical、vPortExitCritical、vPortGenerateSimulatedInterrupt、xPortStartScheduler——这些由具体架构移植代码提供不属于内核通用部分Tick 钩子vApplicationTickHook——由应用层FreeRTOSConfig 的configUSE_TICK_HOOK提供内核其他模块的辅助函数pvTaskIncrementMutexHeldCount、vTaskInternalSetTimeOutState、vTaskMissedYield、vTaskPlaceOnEventList、vTaskPriorityDisinheritAfterTimeout、xTaskGetCurrentTaskHandle、xTaskPriorityDisinherit、xTaskPriorityInherit、xTaskRemoveFromEventList、xTaskResumeAll——这些在tasks.c中定义但不在本证明的链接范围内。cbmc-viewer在生成报告时会读取该 JSON若这些函数在验证结果中确实未被实现报告将其视为预期缺失而非错误反之若出现预期之外的无定义函数则会被标记为问题。这正是 FreeRTOS CBMC 证明体系控制抽象边界的机制——tasks.c依赖的边界被明确登记在案从而把内存安全的验证范围精确限定在vTaskSuspendAll及其直接可达的内核代码上。CBMC 基础设施的更多细节包括patches目录中用于去除源码static/volatile限定符的补丁机制可参阅 Test/CBMC/README.md其include目录中的 cbmc.h 还提供了nondet_*非确定性值生成函数、safeMalloc以及pvPortMalloc/vPortFree的桩实现供其他更复杂的证明复用。对比 TaskResumeAll为什么挂起证明比恢复证明简单把视线投向与TaskSuspendAll配对的 TaskResumeAll 证明能更深刻地理解本证明的价值。xTaskResumeAll()的证明 README 明确列出了大量假设We assume that task lists are initialized and filled with a few list items. We also assume that some global variables are set to a nondeterministic value, except foruxSchedulerSuspendedwhich cannot be 0 andxPendedTickswhich is either1... or0.其 harnessTaskResumeAll_harness.c也需要先调用vSetGlobalVariables()与xPrepareTaskLists()两个测试辅助函数完成状态准备且只有xTasksPrepared ! pdFAIL时才真正调用目标函数void harness() { BaseType_t xTasksPrepared; vSetGlobalVariables(); xTasksPrepared xPrepareTaskLists(); if( xTasksPrepared ! pdFAIL ) { xTaskResumeAll(); } }此外TaskResumeAll还提供了两套配置default与useTickHook1后者设置configUSE_TICK_HOOK1并声明vApplicationTickHook、vPortEnterCritical、vPortExitCritical、vPortGenerateSimulatedInterrupt等函数为内存安全且无相关副作用。两相对照可以得出一个清晰的结论vTaskSuspendAll()功能是递增挂起计数、标记调度器暂停路径短、无循环、无参数、无前置条件因此证明天然无需假设——--unwind 1即可覆盖xTaskResumeAll()恢复调度时要遍历挂起期间累积的任务列表、处理待处理 tick、恢复被抢占的上下文路径复杂且依赖链表状态因此必须构造初始状态、约束关键变量取值并区分不同配置。这也从侧面说明CBMC 证明的复杂度与目标函数的控制流复杂度强相关零假设证明是一种需要函数本身结构足够简单才能获得的奢侈。在本地运行该证明FreeRTOS 的 CBMC 证明支持在 Linux 与 macOS 上运行Windows 用户可通过 WSL运行前需满足以下前置条件详见 Test/CBMC/README.md工具链Python 3.7、Make64 位机器上还需安装 32 位 gcc 库如 Linux 下sudo apt-get install gcc-multilibCBMC 本体确保cbmc、goto-ccWindows 为goto-cl、goto-instrument可从命令行直接调用cbmc-viewer用于生成 HTML/JSON 报告的辅助工具需确保cbmc-viewer命令可用子模块在仓库根目录执行git submodule update --init --recursive --checkout拉取内核子模块。完成准备后按以下步骤运行# 进入 proofs 目录生成各证明的 Makefile cd FreeRTOS/Test/CBMC/proofs python3 prepare.py # 进入目标证明目录并执行 cd Task/TaskSuspendAll make运行结束后报告会生成在证明目录下的html/子目录中与TaskCreate等证明的产物结构一致HTML 报告Task/TaskSuspendAll/html/html/index.html可在浏览器打开成功时Errors一栏显示NoneJSON 报告Task/TaskSuspendAll/html/json/。对于本证明make会依次完成goto-cc编译 harness 与内核源码生成.goto文件 →cbmc结合--unwind 1对vTaskSuspendAll()做有界模型检验 →cbmc-viewer依据 cbmc-viewer.json 生成报告并核对缺函数清单。总结TaskSuspendAll证明是 FreeRTOS CBMC 内存安全证明体系中最小可行证明的典型样本它以一段仅含单次调用的 harness、一份 7 行的 JSON 配置和一个缺函数清单完整覆盖了vTaskSuspendAll()的内存安全验证并明确给出了零假设、零抽象这一可复现的强结论。对于希望为自研 RTOS 或 FreeRTOS 扩展接口引入形式化验证的开发者这个证明提供了一个极佳的入手模板当目标函数无参数、无循环、无复杂全局状态时可以期望实现零假设证明一旦函数涉及链表遍历、条件循环或多配置宏如TaskResumeAll与TaskIncrementTick就必须在 harness 中显式准备状态、约束非确定性变量并通过Configurations.json拆分配置始终用expected-missing-functions明确声明抽象边界让验证范围与报告结论保持透明一致。【免费下载链接】FreeRTOSClassic FreeRTOS distribution. Started as Git clone of FreeRTOS SourceForge SVN repo. Submodules the kernel.项目地址: https://gitcode.com/GitHub_Trending/fr/FreeRTOS创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考