Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何克服snprintf在不同类UNIX操作系统中的不一致行为?_C_Cross Platform_Buffer Overflow_Buffer Overrun - Fatal编程技术网

C 如何克服snprintf在不同类UNIX操作系统中的不一致行为?

C 如何克服snprintf在不同类UNIX操作系统中的不一致行为?,c,cross-platform,buffer-overflow,buffer-overrun,C,Cross Platform,Buffer Overflow,Buffer Overrun,根据手册页,snprintf返回从glibc版本2.2开始写入的字节数。但在libc2.2和HP-UX的较低版本上,它返回一个正整数,这可能导致缓冲区溢出 如何克服这一点并编写可移植代码 编辑:为了更加清晰 这段代码在lib2.3中运行良好 if ( snprintf( cmd, cmdLen + 1, ". %s%s", myVar1, myVar2 ) != cmdLen ) { fprintf( stderr, "\nError: Unable to c

根据手册页,snprintf返回从glibc版本2.2开始写入的字节数。但在libc2.2和HP-UX的较低版本上,它返回一个正整数,这可能导致缓冲区溢出

如何克服这一点并编写可移植代码

编辑:为了更加清晰

这段代码在lib2.3中运行良好

    if ( snprintf( cmd, cmdLen + 1, ". %s%s", myVar1, myVar2 )  != cmdLen )
    {
        fprintf( stderr, "\nError: Unable to  copy bmake command!!!");
        returnCode = ERR_COPY_FILENAME_FAILED;
    }

在Linux上,它返回字符串(10)的长度。但同一代码返回的正数大于HP-UX机器上打印的字符数。希望这个解释很好。

< P>我已经找到了一种预测和/或限制SaveTf和相关函数返回的字符数的便携式方法,但是效率很低,很多人认为它不优美。 您要做的是创建一个临时文件,将tmpfile()、fprintf()设置为该临时文件(可靠地返回写入的字节数),然后将全部或部分文本倒带并读取到缓冲区中

例如:

int my_snprintf(char *buf, size_t n, const char *fmt, ...)
{
    va_list va;
    int nchars;
    FILE *tf = tmpfile();

    va_start(va, n);
    nchars = vfprintf(tf, fmt, va);
    if (nchars >= (int) n)
        nchars = (int) n - 1;
    va_end(va);
    memset(buf, 0, 1 + (size_t) nchars);

    if (nchars > 0)
    {
        rewind(tf);
        fread(buf, 1, (size_t) nchars, tf);
    }

    fclose(tf);

    return nchars;   
}

您可以创建一个snprintf包装器,当缓冲区中没有足够的空间时,该包装器为每种情况返回-1

有关更多文档,请参阅。它也有一个威胁所有案件的例子

  while (1) {
      /* Try to print in the allocated space. */
      va_start(ap, fmt);
      n = vsnprintf (p, size, fmt, ap);
      va_end(ap);
      /* If that worked, return the string. */
      if (n > -1 && n < size)
         return p;
      /* Else try again with more space. */
      if (n > -1)    /* glibc 2.1 */
         size = n+1; /* precisely what is needed */
      else           /* glibc 2.0 */
         size *= 2;  /* twice the old size */
      if ((np = realloc (p, size)) == NULL) {
         free(p);
         return NULL;
      } else {
         p = np;
      }
   }
while(1){
/*尝试在分配的空间中打印*/
va_启动(ap、fmt);
n=vsnprintf(p、尺寸、fmt、ap);
va_端(ap);
/*如果有效,则返回字符串*/
如果(n>-1&&n-1)/*glibc 2.1*/
大小=n+1;/*正是所需的*/
else/*glibc 2.0*/
尺寸*=2;/*旧尺寸的两倍*/
if((np=realloc(p,size))==NULL){
自由基(p);
返回NULL;
}否则{
p=np;
}
}

您是否考虑过printf的可移植实现?我前段时间找了一个,最后选择了三人组


你的问题还不清楚。与之相关的人这样说:

函数snprintf()和vsnprintf()的写入长度不超过大小字节(包括 尾随的“\0”)。如果由于此限制而截断了输出,则返回值为字符数(不包括尾随“\0”),如果有足够的可用空间,将写入最终字符串。因此,大小大于等于的返回值意味着输出被截断。

因此,如果您想知道输出是否被截断:

int ret = snprintf(cmd, cmdLen + 1, ". %s%s", myVar1, myVar2 ) == -1)
if(ret == -1 || ret > cmdLen)
{
    //output was truncated
}
else
{
    //everything is groovy
}

请改用更高级的asprintf()


这是一个GNU扩展,但如果它本机不可用,则值得复制到目标平台。

在*printf可移植性方面存在大量问题,实际上,您可能希望遵循以下三种途径之一:

  • 需要c99兼容的*printf,因为9年对任何人来说都足够了,否则就说平台坏了

  • 有一个my_snprintf(),其中包含一堆针对您想要支持的特定平台的#ifdef,所有调用下面的vsnprintf()(了解最低公分母就是您所拥有的)

  • 只需随身携带一份vsnprintf()的副本和代码,对于简单的用例,它实际上是,对于其他您可能想查看的用例,您将免费获得客户格式化程序

  • …正如其他人所建议的,您可以进行黑客合并#1和#2,仅针对-1情况,但这是有风险的,因为c99*printf在某些情况下可以/确实返回-1


    就我个人而言,我建议只使用,它为您提供简单的解决方法,并免费提供托管字符串。如果你真的在乎,你可以结合。

    你能澄清一下你的问题吗?目前尚不清楚返回值类型如何导致缓冲区溢出。这不起作用,因为当前有效的snprintf()会在出现错误时返回-1。当它分配两倍于旧大小(/*glibc 2.0*/comment)时,会处理-1情况。printf函数有两种行为:1。它返回-1,告诉您缓冲区不够大2。它返回所需的字节数(您需要进行比较以确定是否正确),asprintf()实际上并不好,因为它根本不是标准的,而且行为也不一样。另外,您得到的不是一个有用的管理字符串,如ustr_dup_fmt()等。