蓝牙耳机|strncpy可能导致的缓冲区溢出问题

蓝牙耳机|strncpy可能导致的缓冲区溢出问题

文章图片

蓝牙耳机|strncpy可能导致的缓冲区溢出问题

文章图片


如果你有幸阅读strncpy的文档 , 则你会发现它有一种很奇怪的行为 , 我们先看看下面的描述:

下面 , 我们分几种情况来讨论实际执行的结果:

为什么这个函数有如此怪异的行为?让我们回到 UNIX 的早期 。就我个人而言 , 我只能想到 System V的年代 。 在 System V 中 , 文件名最长可达 14 个字符 。任何更长的都被截断为 14 个字符 。 存储文件名的字段正好是 14 个字符 , 而不是 15. 这意味着其中包含了空终止符 , 这节省了一个字节 。以下是一些文件名及其对应的目录条目:

请注意 , 由于截断 , newsgroups.old 和 newsgroups.old.backup 实际上是相同的文件名 。 太长的名字会被默默地截断 , 这并没有引发错误 。 这在历史上一直是意外数据丢失错误的根源 。 文件系统使用 strncpy 函数将文件名存储到目录条目中 。 这解释了 strcpy 奇怪行为的一部分 , 就是为什么它在目标填充时不会以空值终止 。 数组末尾隐含了空终止符 。(它还解释了静默文件名截断行为 。 )但是为什么要使用空填充短文件名呢?因为这样可以更快地扫描文件名 。 如果你保证所有的“垃圾字节”都是空的 , 那么你可以使用 memcmp 来比较它们 。
出于兼容性的原因 , C 语言委员会决定将 strncpy 的这种古怪行为发扬光大 。 那今天文章的标题是什么意思呢:试图防止缓冲区溢出的代码是如何导致缓冲区溢出的?
在网络上有这样一个例子:观察它使用 _tcsncpy 来填充 lpstrFile 和 lpstrFileTitle , 注意不要溢出缓冲区 。 这很好 , 但如果字符串太长 , 它也会省略空终止符 。 调用者可以很好地将结果从该缓冲区复制到第二个缓冲区 。 但是 lstrFile 缓冲区缺少适当的空终止符 , 因此超过了调用者指定的长度 。 结果:第二个缓冲区溢出 。
在另外一个例子中 , 请观察该函数使用 _tcsncpy 将结果复制到输出缓冲区 。 这位作者注意到 strncpy 系列函数的古怪行为 , 并在缓冲区末尾手动添加了一个空终止符 。 但是如果 ccTextMax = 0 呢?然后尝试强制空终止符取消引用超出数组的开头并破坏随机字符 。
那今天文章的结论是什么? 就个人而言 , 我的结论是 , 如果你正在处理以空字符结尾的字符串 , 那么请避免使用 strncpy 及其所有变种 。尽管名称中有“str” , 但这些函数不会产生以 NULL 结尾的字符串 。他们将一个以 NULL 结尾的字符串转换为一个原始字符缓冲区 。在预期以空结尾的字符串作为第二个缓冲区的地方使用它们是完全错误的 。如果源字符串太长 , 你不仅无法获得正确的空终止符 , 而且如果源字符串太短 , 你又将获得不必要的空终止符 。
总结基于我开发拓扑梅尔智慧办公平台的经验 , 对于字符串复制 , 我一直坚持使用_tcscpy_s , 好像目前也没发现什么大问题 , 运行起来还颇为稳定 。
最后Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一 , 里面有很多关于Windows的小知识 , 对于广大Windows平台开发者来说 , 确实十分有帮助 。
本文来自:《How can code that tries to prevent a buffer overflow end up causing one?》
【蓝牙耳机|strncpy可能导致的缓冲区溢出问题】