2012-10-05 79 views
37

我很难理解你为什么需要asprintf。 这里手册中它说为什么要使用Asprintf?

功能asprintf()和vasprintf()被sprintf的类似物(3)和 vsprintf中(3),不同之处在于它们分配一个字符串大到足以容纳 输出包括终止空字节,并通过第一个参数向它返回一个指针 。这个指针应该被传递给 免费(3),以便在不再需要时释放分配的存储空间。

因此,这里是我想了解的例子:

asprintf(&buffer, "/bin/echo %s is cool", getenv("USER")); 

有什么区别,如果缓冲区分配一个字符串足够大VS说的char * =(字符串)

+5

'asprintf()'和'vasprintf()'是GNU扩展。添加了GNU标签。 – alk

+3

嗯,我不知道提问者是否在这里练习:http://exploit-exercises.com/nebula/level02? – jordanpg

+1

关于此主题的非常好的博客文章可以在这里找到:[内存管理在C和自动](http://insanecoding.blogspot.de/2014/06/memory-management-in-c-和 - auto.html)...顺便说一句。完整的博客是值得的 – antibus

回答

82

如果使用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标准的一部分。

+0

谢谢你的回答。清理了很多东西 –

+1

另外,[你不应该在C语言中输入'malloc'(和family)的结果(http://www.stackoverflow.com/questions/605845/do-i-cast-the-结果-的-的malloc)。 –

+0

非常迟到我固定@ user694733的点。 – slim

18

的好处是安全。

许多程序允许系统漏洞发生时,程序员提供的缓冲区溢出时充满用户提供的数据。

拥有asprintf为您分配缓冲保证不会发生。

但是,您必须检查返回值asprintf以确保内存分配实际上成功。请参见http://blogs.23.nu/ilja/2006/10/antville-12995/

+0

我记得在这个模糊的阅读。这是使用asprintf的唯一原因吗? –

+2

@BrandonLing,在很多情况下,它会缩短你的代码! – Alnitak

+4

@BrandonLing:它消除了代码重复 - 当你想要一个永不截断的'sprintf'时,你可以多次编写自己的函数来完成这个任务,所以现在你已经把它全部包装在一个单独的,这是以便携性为代价的。 –