Cake – C23 及以后(2023)

将 Rust 风格的所有权和内存安全检查引入 C 的 Cake C23 前端,既引发了兴趣,也带来了怀疑。支持者认为,编译期跟踪资源生命周期(例如 `malloc`/`free`、`fopen`/`fclose`)很有价值,而且可以叠加到现有代码之上,并在 GCC/Clang 下“编译掉”;批评者则质疑这些注解的可组合性、将大型库改造为此类注解体系的现实性,以及这种部分启用、可选择的安全方案是否值得其复杂度。讨论经常把这一思路与 Rust、自定义分配器和 mempool 等替代方案对比,并引出一个更广泛的问题:C 应该通过渐进方式增强,还是直接转向本身就具备内存安全性的语言。

Cake 中的所有权模型

  • Cake 为 C23 增加了 _Owner_View 等限定符和流分析,用于检查资源生命周期(例如 FILE * owner),主要关注时间安全(double free / use-after-free),而不是空间边界。
  • 所有权是类型系统的一部分,而不是属性,因此要返回一个 owner,必须给函数返回类型加注解;移动会被跟踪,而那些从 owner 移走后的作用域不会被强制要求“销毁”。
  • 该系统也可以把非指针值(句柄)视为 owner,从而支持自定义分配器和基于句柄的设计。

改造旧代码与可组合性

  • 一个强烈的担忧是所有权会“感染” API:一旦某个函数返回 owner,它的调用者以及调用者的调用者都必须采用注解。
  • Cake 的作者指出这与在头文件里加入 const 很相似:改动会广泛传播,但最终会稳定下来。
  • 检查默认是关闭的;包含 ownership.h 并定义 __OWNERSHIP_H__ 会把它们打开。宏允许用不支持所有权的编译器编译同一份代码。
  • 一些模式(例如链表)被展示为可以干净地工作;Cake 自己代码中的某些函数因为过于别扭而禁用了检查。

安全保证与局限

  • 当前重点是时间安全;越界和一般性的 UB 还没有处理。可空引用和类似生命周期的分析已在计划中,但尚未完成。
  • 静态分析被视为有价值,尤其适用于那些很少执行的路径,因为运行时工具可能永远触发不到它们。
  • 讨论中存在争议:这种“可选”的安全性(按文件定义、还能关闭检查)是否真的有吸引力,还是应该直接追求完整的内存安全。

与 Rust、RAII、mempool、isoheap 的比较

  • 讨论中多次把它与 Rust 的所有权/借用模型相比较:在 move 和 drop 上有相似之处,但在动态 drop 语义和显式生命周期上有所不同。
  • Cake 与 C++ RAII 不同:析构并非无条件发生;是否需要销毁由流分析决定。
  • 有人认为好的 mempool 或 isoheap 也能达到类似安全性;也有人反驳说它们无法广泛处理 UB,而且并不等同于静态所有权检查。
  • “半吊子”方案仍然允许 bug,与会迫使架构改变的严格模型之间存在张力。

工具链、集成与生态问题

  • Cake 是一个独立的 C23 前端,可以输出 C99/C89,既可用作编译器,也可用作静态分析器。
  • 通过使用空的所有权宏,它可以与 GCC/Clang 共存;也有人对类似插件的集成方式感兴趣。
  • 实际成功取决于能否给复杂的真实库(例如 OpenSSL)添加注解,这一点被承认是后续工作。