文章摘要
文章讨论了C语言中带大小检查的数组参数特性,这是一种增强类型安全性的语法扩展,允许函数声明时指定数组参数的大小,编译器可据此进行静态检查。该特性旨在减少缓冲区溢出等潜在错误。
文章总结
C语言中带尺寸检查的数组参数
本文探讨了C语言中一个鲜为人知的特性——通过static关键字在函数参数中声明数组尺寸检查,以提高代码安全性。
背景
在Linux内核加密层开发中,Ard Biesheuvel发现函数xchacha20poly1305_encrypt()存在安全隐患:虽然函数原型明确指定了nonce和key参数的数组尺寸,但编译器不会检查传入数组的实际大小。这可能导致参数顺序错误等漏洞。
解决方案讨论
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的补丁系列。
评论总结
以下是评论内容的总结:
对数组检查语法的批评
有评论指出该语法在1999年就被认为是不好的设计,引用加拿大C工作组Raymond Mak的话:"There was a unanimous vote that the feature is ugly..."(评论1)替代方案建议
- 建议使用结构体包装:"Better option: just wrap it in a unique struct"(评论2)
- 指针到数组被认为更正确:"Pointer to array is not only type-safe, it is also objectively correct..."(评论3)
编译器扩展
GCC支持引用函数参数的扩展,但Clang不支持:"GCC also has an extension to support references..."(评论4)标准问题
编译器不强制要求警告数组过小的情况,官方认为这是未定义行为:"The official stance is that it's simply undefined behaviour..."(评论5)类型定义问题
数组类型定义会隐式退化为指针,可能造成误解:"It looks as if thing_t can be passed by value, but since it is an array..."(评论8)静态关键字的复用
C语言中static关键字被多次复用:"This would not be the first time that the 'static' keyword..."(评论10)其他建议
- 使用固定大小结构体:"You could just declare struct Nonce..."(评论11)
- 静态不能用于数组类型定义是限制:"Unfortunately you cannot use static in array typedefs..."(评论12)