我很难理解为什么需要asprintf。
在手册中它说
The functions asprintf() and vasprintf() are analogs of sprintf(3) and
vsprintf(3), except that they allocate a string large enough to hold
the output including the terminating null byte, and return a pointer
to it via the first argument. This pointer should be passed to
free(3) to release the allocated storage when it is no longer needed.
因此,这是我尝试理解的示例:
1
| asprintf (&buffer ,"/bin/echo %s is cool", getenv("USER")); |
如果缓冲区分配的字符串足够大而与说char * =(string)有什么区别?
-
asprintf()和vasprintf()是GNU扩展。 添加了GNU标签。
-
嗯,我想知道问问者是否正在这里进行练习:exploit-exercises.com/nebula/level02?
-
关于此主题的非常好的博客文章可以在这里找到:c-and-auto中的内存管理... btw。 完整的博客值得阅读
如果使用sprintf()或vsprintf(),则需要首先分配一个缓冲区,并且需要确保该缓冲区足够大以包含sprintf写入的内容。否则,sprintf()将很乐意覆盖缓冲区末尾以外的所有内存。
1 2 3
| char* x = malloc(5 * sizeof(char));
// writes"123456" +null but overruns the buffer
sprintf(x ,"%s%s%s","12","34","56"); |
...在分配给x的空间的末尾写入'6'和终止null,这会破坏某些其他变量或导致分段错误。
如果幸运的话,它会在分配的块之间践踏内存,这不会造成伤害-这次。这会导致间歇性错误,这是最难诊断的错误。最好使用诸如ElectricFence之类的工具,该工具会导致超速运行失败。
输入时间过长的非恶意用户可能会导致程序异常运行。恶意用户可以利用此方法将自己的可执行代码获取到系统中。
一种防止这种情况的方法是使用snprintf(),它会将字符串截断为您提供的最大长度。
1 2
| char *x = malloc(5 * sizeof(char));
int size = snprintf(x , 5,"%s%s%s","12","34","56"); // writes"1234" + null |
返回值size是如果有可用空间将要写入的长度-不包括终止null。
在这种情况下,如果size大于或等于5,则说明发生了截断-如果不想截断,则可以分配新的字符串并再次尝试snprintf()。
1 2 3 4 5 6
| 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 , size + 1 ,"%s%s%s","12","34","56");
} |
(这是一个非常幼稚的算法,但是它说明了这一点。其中可能还存在一些错误,这进一步说明了这一点-这些东西很容易搞砸。)
asprintf()一步为您完成此操作-计算字符串的长度,分配该内存量,然后将字符串写入其中。
1 2
| char *x;
int size = asprintf(&x,"%s%s%s","12","34","56"); |
在所有情况下,完成x后,都需要释放它,否则会泄漏内存:
asprintf()是隐式的malloc(),因此您必须检查它是否起作用,就像使用malloc()或任何其他系统调用一样。
1 2 3
| if (size == -1 ) {
/* deal with error in some way */
} |
请注意,asprintf()是libc的GNU和BSD扩展的一部分-您无法确定它是否在每个C环境中都可用。 sprintf()和snprintf()是POSIX和C99标准的一部分。
-
感谢您的回答。清理了很多东西
-
同样,您不应该在C中强制转换malloc(和族)的结果。
-
请稍等,如果size是写有不带终止null的字符,您是否应该重新分配(size+1) * sizeof(char)?
-
@JoachimSauer谢谢。啊,C :)-至少证明了asprintf有用的原因。老方法确实很容易搞砸。
-
值得注意的是,asprintf不是C或POSIX标准的一部分,而是GCC和BSD扩展。尽管很有用-这是所要问的问题-但应充分意识到C代码的可移植性下降。 linux.die.net/man/3/asprintf
-
5年后才缓和,并删除了malloc()上的演员表
-
我想我在snprintf片段中发现了一些问题:1.您想将BUF_LEN传递给第一个snprintf(),而不是5! 2.您需要执行x = realloc(x, (size + 1))! realloc接受一个指针,而不是一个指针! 3.第二个snprintf调用应该是(size + 1),而不是5!
好处是安全。
当程序填充了用户提供的数据时,程序员提供的缓冲区就会溢出,从而导致许多程序被系统利用。
使asprintf为您分配缓冲区可以保证不会发生。
但是,您必须检查asprintf的返回值以确保内存分配实际成功。参见http://blogs.23.nu/ilja/2006/10/antville-12995/
-
我记得模糊地读过这篇文章。这是使用asprintf的唯一原因吗?
-
@BrandonLing很好,在许多情况下,它也会使您的代码更短!
-
@BrandonLing:它消除了代码重复-很多情况下,当您想要一个永不截断的sprintf时,您不得不编写自己的函数来执行此操作,因此,现在将它们全部包装在一个现成的函数中,以便携性为代价。