Linux磁盘剩余空间获取方法及long返回值类型的容量上限问题
问题解答
会,这是原代码非常典型的溢出漏洞,具体说明如下:
- 首先纠正你对
f_bavail类型的误解:根据POSIX标准,struct statvfs里的f_bavail类型不是unsigned long,是fsblkcnt_t类型,这是一个平台相关的无符号整数类型,32位系统下通常是32位无符号数,64位系统下通常是64位无符号数。 - 32位系统环境下:
long是32位有符号整数,最大值仅为2^31-1(约2GB)。常见的文件系统块大小为4KB,只要磁盘剩余空间超过2GB,f_bsize * f_bavail的结果就会超过32位long的承载上限,出现溢出截断,返回完全错误的负值或者小数值。 - 64位系统环境下:主流Linux采用LP64模型,
long是64位有符号整数,最大值为263-1(约9EB),目前民用级存储暂时不会触及这个上限,但如果是面向大规模分布式存储场景,依然存在溢出风险。另外还有一个隐性问题:两个无符号整数相乘的结果是无符号类型,如果乘积刚好超过263-1,强制转换为有符号long后会变成负数,逻辑完全错误。
修正方案
可以参考如下代码规避溢出问题:
#include <sys/statvfs.h> #include <stdint.h> #include <stdio.h> uint64_t GetAvailableSpace(const char* path, int* err) { struct statvfs stat; if (statvfs(path, &stat) != 0) { if (err) *err = -1; return 0; } uint64_t bsize = stat.f_bsize; uint64_t bavail = stat.f_bavail; // 溢出校验 if (bavail > UINT64_MAX / bsize) { if (err) *err = -2; return UINT64_MAX; } if (err) *err = 0; return bsize * bavail; } int main(int argc, const char *argv[]) { if (argc < 2) { printf("Usage: %s <path>\n", argv[0]); return 1; } int err; uint64_t avail = GetAvailableSpace(argv[1], &err); if (err != 0) { printf("Get available space failed, err: %d\n", err); return 1; } printf("The remaining size is %lu \n", (unsigned long)avail); return 0; }
内容的提问来源于stack exchange,提问作者user1538798
相关产品推荐
相关产品推荐

