为什么_splitpath_s()使用自定义大小的字符串缓冲区来返回驱动器号



在阅读_splitpath_s()的文档时,一个小细节引起了我的注意。它在其1st参数中获取磁盘项的路径(例如,C:\Temp\MyFile.exe),然后将其拆分为驱动器目录扩展名。然而,奇怪的是,它要求字符串缓冲区的长度,该缓冲区将在其3rd参数中保存驱动器的名称作为回报。

据我所知,驱动器号只能是两个字母的字符串;后跟分号的字母,如A:B:C:等。因此,在所有情况下,它都必须是两个字符的字符串。但如果是这样,_splitpath_s()为什么要求驱动器号的长度?有没有哪种驱动器号可以采用不同的格式?如果它不询问它的长度,只假设它是2,那么在最坏的情况下会发生什么问题?

errno_t _splitpath_s(
   const char * path,
   char * drive,
   size_t driveNumberOfElements,
   char * dir,
   size_t dirNumberOfElements,
   char * fname,
   size_t nameNumberOfElements,
   char * ext, 
   size_t extNumberOfElements
);

_s函数的重点是对缓冲区溢出保持偏执。因此,所有缓冲区都应该与一个大小相关联。

您建议使用两个字符的字符串,这意味着冒号将被省略(从使用角度来看,这将是令人讨厌的),或者意味着字符串没有以NUL结尾,这可能是出乎意料的(尤其是因为它与所有其他输出参数不一致,NUL终止),然后可能导致其他安全漏洞。

即使您修改了您的建议,使用三个字符而不是两个字符的固定大小缓冲区,在C中,向函数声明数组参数实际上也没有任何作用;编译器不会强制要求参数是大小正确的数组。也就是说,一个类似于的函数

 void foo(int array[3]);

实际上与没有什么不同

 void foo(int* array);

如果_splitpath_s不采用driveNumberOfElements参数,那么调用方将更容易意外地传递过小的缓冲区。虽然调用方在当前形式下仍然可以这样做,但显式driveNumberOfElements参数的存在应该会让调用方注意到这一点。

最后,从理论上讲,有朝一日驱动器可能不会局限于单个字符,因此采用driveNumberOfElements参数的_splitpath_s版本更适合未来使用。(然而,在实践中,这样的更改会破坏许多现有代码。)

最新更新