Hacker News 中文摘要

RSS订阅

C语言中的定长数组参数 -- Checked-size array parameters in C

文章摘要

文章讨论了C语言中带大小检查的数组参数特性,这是一种增强类型安全性的语法扩展,允许函数声明时指定数组参数的大小,编译器可据此进行静态检查。该特性旨在减少缓冲区溢出等潜在错误。

文章总结

C语言中带尺寸检查的数组参数

本文探讨了C语言中一个鲜为人知的特性——通过static关键字在函数参数中声明数组尺寸检查,以提高代码安全性。

背景

在Linux内核加密层开发中,Ard Biesheuvel发现函数xchacha20poly1305_encrypt()存在安全隐患:虽然函数原型明确指定了noncekey参数的数组尺寸,但编译器不会检查传入数组的实际大小。这可能导致参数顺序错误等漏洞。

解决方案讨论

Biesheuvel最初提出通过增加指针间接层级来强制尺寸检查: c const u8 (*nonce)[XCHACHA20POLY1305_NONCE_SIZE]

但Jason Donenfeld指出,C标准中已存在更直接的解决方案——使用static关键字: c const u8 nonce[static XCHACHA20POLY1305_NONCE_SIZE]

这种方法不需要修改调用方代码,且能在数组过小时生成编译器警告。虽然GCC的数组尺寸警告曾被关闭(6.8版本因误报问题),但Linus Torvalds表示支持使用这个"语法设计糟糕但实用"的特性。

技术细节

  • static方案只检查最小尺寸,不要求精确匹配
  • 相比指针方案,static更简洁且不影响调用方
  • 内核已有部分代码使用此特性(如虚拟终端驱动中的getconsxy()

争议与讨论

评论中开发者们就以下问题展开讨论: 1. [n][static n]的实际效果差异 2. GCC和Clang对这两种语法的支持程度不同 3. static语法可能带来的非空指针假设等副作用 4. 最终内核采用了at_least宏来包装此特性,提高可读性

结论

尽管这个C语言特性存在设计争议,但它为提高内核代码安全性提供了一个实用工具。随着相关补丁的合并,这一"隐晦技巧"有望在内核中得到更广泛的应用。

编辑注:最新内核代码已改用at_least宏,示例可参考Eric Biggers的补丁系列。

评论总结

以下是评论内容的总结:

  1. 对数组检查语法的批评
    有评论指出该语法在1999年就被认为是不好的设计,引用加拿大C工作组Raymond Mak的话:"There was a unanimous vote that the feature is ugly..."(评论1)

  2. 替代方案建议

    • 建议使用结构体包装:"Better option: just wrap it in a unique struct"(评论2)
    • 指针到数组被认为更正确:"Pointer to array is not only type-safe, it is also objectively correct..."(评论3)
  3. 编译器扩展
    GCC支持引用函数参数的扩展,但Clang不支持:"GCC also has an extension to support references..."(评论4)

  4. 标准问题
    编译器不强制要求警告数组过小的情况,官方认为这是未定义行为:"The official stance is that it's simply undefined behaviour..."(评论5)

  5. 类型定义问题
    数组类型定义会隐式退化为指针,可能造成误解:"It looks as if thing_t can be passed by value, but since it is an array..."(评论8)

  6. 静态关键字的复用
    C语言中static关键字被多次复用:"This would not be the first time that the 'static' keyword..."(评论10)

  7. 其他建议

    • 使用固定大小结构体:"You could just declare struct Nonce..."(评论11)
    • 静态不能用于数组类型定义是限制:"Unfortunately you cannot use static in array typedefs..."(评论12)