如果使用sprintf()或vsprintf(),则需要首先分配缓冲区,并且需要确保缓冲区足够大以包含sprintf写入的内容。否则,sprintf会高兴地覆盖超出缓冲区末端的内存。
char* x = malloc(5 * sizeof(char));
sprintf(x,"%s%s%s", "12", "34", "56"); // writes "123456" +null but overruns the buffer
...写入“6”和终止null
超出分配给x
的空间的端部,或者破坏某些其他变量,或引起段故障。
如果幸运的话,它会在分配的块之间的内存上践踏,并且不会造成伤害 - 这一次。这会导致间歇性的错误 - 最难诊断的错误。使用类似ElectricFence这样的工具会很好,它会导致超限失效。
提供超长输入的非恶意用户可能会导致程序以意外的方式运行。恶意用户可以利用这种方式将自己的可执行代码加入系统。
对此的一个警告是使用snprintf()
,它将字符串截断为您提供的最大长度。
char *x = malloc(5 * sizeof(char));
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56"); // writes "1234" + null
返回值size
是长度本来书面如果空间是可利用的 - 不包括终止空。
在这种情况下,如果size
大于或等于5,那么你知道,截断发生 - 如果你不想截断,你可以分配一个新的字符串,然后再次尝试snprintf()
。
char *x = malloc(BUF_LEN * sizeof(char));
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56");
if(size >= BUF_LEN) {
realloc(&x,(size + 1) * sizeof(char));
snprintf(x, 5, "%s%s%s", "12", "34", "56");
}
(这是一个非常天真的算法,但它说明了这一点)
asprintf()
做这一步为您服务 - 计算字符串的长度,分配的内存量,并写入字符串进去。
char *x;
int size = asprintf(&x, "%s%s%s", "12", "34", "56");
在所有情况下,一旦你与x
完成,你需要释放它,或者你内存泄漏:
free(x);
asprintf()
一个隐含的malloc()
,所以你必须检查它的工作,就像使用malloc()
或任何其他系统调用一样。
if(size == -1) {
/* deal with error in some way */
}
注意asprintf()
是GNU和BSD扩展的一部分到libc - 你不能肯定它会在每一个C环境中使用。 sprintf()
和snprintf()
是POSIX和C99标准的一部分。
'asprintf()'和'vasprintf()'是GNU扩展。添加了GNU标签。 – alk
嗯,我不知道提问者是否在这里练习:http://exploit-exercises.com/nebula/level02? – jordanpg
关于此主题的非常好的博客文章可以在这里找到:[内存管理在C和自动](http://insanecoding.blogspot.de/2014/06/memory-management-in-c-和 - auto.html)...顺便说一句。完整的博客是值得的 – antibus