使 VLA 比 argv[1] 稍长是否安全?
is it safe to make a VLA slightly longer than argv[1]?
示例代码,将 argv[1]
视为文件路径,将其扩展名替换为 .png
或在找到 none 时附加它:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc != 2)
return 1;
char *lastdot = strrchr(argv[1], '.');
size_t len = lastdot ? (lastdot - argv[1]) : strlen(argv[1]);
char outpath[len + sizeof(".png")];
// ^ this is the important part
memcpy(outpath, argv[1], len);
memcpy(outpath + len, ".png", sizeof(".png"));
printf("%s\n", outpath);
}
我主要担心的是 argv[1]
可能小到不会导致 OS 本身出错,但是 ".png"
连接添加的额外 4 个字节分配VLA会不会导致栈溢出?
问题是我不太确定 argv
或 VLA 的成员的大小是如何受到限制的。
显然,对于静态数组大小,PATH_MAX
等常量不可信,因此它要么是这个,要么是 malloc
。
您的担心是真实的:C 标准中没有任何内容保证您的程序可用的堆栈 space 足以为一个非常长的命令行参数加上 4 个字节分配一个大的 VLA。实际上,在现代操作系统上,堆栈 space 通常至少为 1 兆字节,命令行参数限制在大约 100 KB 以内......所以你应该是安全的。
另请注意,有些编译器根本不支持 VLA,因此从堆中分配是一种更可移植的方法。
顺便说一句,您可以修改程序以完全避免此问题:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc != 2)
return 1;
char *lastdot = strrchr(argv[1], '.');
int len = lastdot ? lastdot - argv[1] : strlen(argv[1]);
printf("%.*s.png\n", len, outpath);
return 0;
}
示例代码,将 argv[1]
视为文件路径,将其扩展名替换为 .png
或在找到 none 时附加它:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc != 2)
return 1;
char *lastdot = strrchr(argv[1], '.');
size_t len = lastdot ? (lastdot - argv[1]) : strlen(argv[1]);
char outpath[len + sizeof(".png")];
// ^ this is the important part
memcpy(outpath, argv[1], len);
memcpy(outpath + len, ".png", sizeof(".png"));
printf("%s\n", outpath);
}
我主要担心的是 argv[1]
可能小到不会导致 OS 本身出错,但是 ".png"
连接添加的额外 4 个字节分配VLA会不会导致栈溢出?
问题是我不太确定 argv
或 VLA 的成员的大小是如何受到限制的。
显然,对于静态数组大小,PATH_MAX
等常量不可信,因此它要么是这个,要么是 malloc
。
您的担心是真实的:C 标准中没有任何内容保证您的程序可用的堆栈 space 足以为一个非常长的命令行参数加上 4 个字节分配一个大的 VLA。实际上,在现代操作系统上,堆栈 space 通常至少为 1 兆字节,命令行参数限制在大约 100 KB 以内......所以你应该是安全的。
另请注意,有些编译器根本不支持 VLA,因此从堆中分配是一种更可移植的方法。
顺便说一句,您可以修改程序以完全避免此问题:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc != 2)
return 1;
char *lastdot = strrchr(argv[1], '.');
int len = lastdot ? lastdot - argv[1] : strlen(argv[1]);
printf("%.*s.png\n", len, outpath);
return 0;
}