免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2895 | 回复: 4
打印 上一主题 下一主题

[C] vsnprintf 的bug [复制链接]

论坛徽章:
1
15-16赛季CBA联赛之新疆
日期:2017-03-09 12:33:45
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-12-03 18:56 |只看该作者 |倒序浏览
  1. #include <stdio.h>
  2. #include <stdarg.h>
  3. #include <stdlib.h>
  4. #include <string.h>

  5. int simple_assert(const char* file, int lineno, const char* resultstr, const char* fmt, ...)
  6. {
  7.         va_list ap;
  8.         char* fmtstr = NULL;
  9.         int fmtsize = 20;
  10.         int ret = 0;
  11.         va_start(ap, fmt);
  12. try_again:
  13.         if (fmtstr) {
  14.                 free(fmtstr);
  15.         }
  16.         fmtstr = NULL;
  17.         fmtstr = (char*)malloc(fmtsize);
  18.         if (fmtstr == NULL) {
  19.                 fprintf(stderr, "%s:%d can not alloc(%d)\n", file, lineno, fmtsize);
  20.                 abort();
  21.         }

  22.         fprintf(stderr, "fmt (%s)(", fmt);
  23.         vfprintf(stderr, fmt, ap);
  24.         fprintf(stderr, ")\n");
  25.         fflush(stderr);
  26.         ret = vsnprintf(fmtstr, fmtsize - 10, fmt, ap);
  27.         if (ret < 0 || ret >= (fmtsize - 10)) {
  28.                 fprintf(stderr, "expand size %d => %d\n", fmtsize, fmtsize << 1);
  29.                 fmtsize <<= 1;
  30.                 goto try_again;
  31.         }
  32.         va_end(ap);
  33.         ret = strcmp(resultstr, fmtstr);
  34.         if (ret != 0) {
  35.                 fprintf(stderr, "%s:%d (%s) != (%s)\n", file, lineno, resultstr, fmtstr);
  36.                 abort();
  37.         }

  38.         if (fmtstr) {
  39.                 free(fmtstr);
  40.         }
  41.         fmtstr = NULL;
  42.         fmtsize = 0;
  43.         return 0;
  44. }

  45. #define SIMPLE_ASSERT(res,...) simple_assert(__FILE__,__LINE__,res,__VA_ARGS__)


  46. int main(void)
  47. {
  48.         SIMPLE_ASSERT("to display this help information", "%s %s", "to display", "this help information");
  49.         return 0;

  50. }
复制代码
这个是测试vsnprintf 的代码,会引起 segment fault
但这里已经对内存加以限制了,但还是会出现错误

论坛徽章:
0
2 [报告]
发表于 2016-12-04 11:20 |只看该作者
int main(void)
{
        SIMPLE_ASSERT("to display this help information %s %s", "to display", "this help information");
        return 0;

}

程序调用格式有问题,换上面格式看看。

论坛徽章:
0
3 [报告]
发表于 2016-12-04 22:13 |只看该作者
  1. #include <stdio.h>
  2. #include <stdarg.h>
  3. #include <stdlib.h>
  4. #include <string.h>

  5. int simple_assert(const char* file, int lineno, const char* resultstr, const char* fmt, ...)
  6. {
  7.     va_list ap;
  8.     char* fmtstr = NULL;
  9.     int fmtsize ;
  10.     int ret = 0;

  11.         // 通过一次输出,确定 fmtsize 长度
  12.     va_start(ap, fmt);
  13.     fprintf(stdout, "fmt (%s) = (", fmt);
  14.     fmtsize = vfprintf(stdout, fmt, ap);
  15.     fprintf(stdout, ") [%d]\n", fmtsize);
  16.     va_end(ap);
  17.     // 一次的 va_start() 函数调用,也仅仅是提供一次 vsprintf() 函数的支持

  18.         fmtsize += 3;
  19. try_again:
  20.         if( fmtstr ) free(fmtstr);

  21.     fmtstr = (char*)calloc(fmtsize, 1 );
  22.     if (fmtstr == NULL) {
  23.         fprintf(stderr, "%s:%d can not alloc(%d)\n", file, lineno, fmtsize);
  24.         abort();
  25.     }

  26.     va_start(ap, fmt);
  27.     ret = vsnprintf(fmtstr, fmtsize-1, fmt, ap);
  28.     va_end(ap);
  29.     if (ret < 0 || ret >= (fmtsize - 1)) {
  30.         fmtsize <<= 1;
  31.         fprintf(stderr, "expand size %d, %d => %d\n", ret, fmtsize, fmtsize);
  32.         goto try_again;
  33.     }
  34.     fprintf(stdout, "fmtstr = [%d][%d][%s]\n", ret, fmtsize, fmtstr);
  35.     ret = strncmp(resultstr, fmtstr, strlen(resultstr) );
  36.     if (ret != 0) {
  37.         fprintf(stderr, "%s:%d (%s) != (%s)\n", file, lineno, resultstr, fmtstr);
  38.     }
  39.     else
  40.     {
  41.             fprintf(stderr, "[%s] 与 fmtstr 匹配\n", resultstr);
  42.     }

  43.     free(fmtstr);
  44.     return 0;
  45. }

  46. #define SIMPLE_ASSERT(res,...) simple_assert(__FILE__,__LINE__,res,__VA_ARGS__)


  47. int main(void)
  48. {
  49.     SIMPLE_ASSERT("to display this help information", "%s %s", "to display", "this help information");
  50.     return 0;

  51. }
复制代码


使用上述代码,测试看看。

论坛徽章:
1
15-16赛季CBA联赛之新疆
日期:2017-03-09 12:33:45
4 [报告]
发表于 2016-12-05 08:47 |只看该作者
本帖最后由 jeppeter 于 2016-12-05 08:49 编辑
  1. #include <stdio.h>
  2. #include <stdarg.h>
  3. #include <stdlib.h>
  4. #include <string.h>

  5. void debug_buffer(const char* file, int lineno, void* pbuffer, int bufsize, const char* fmt, ...)
  6. {
  7.         va_list ap;
  8.         int i;
  9.         unsigned char* ptr;
  10.         fprintf(stderr, "%s:%d buffer(%p) size(%d)", file, lineno, pbuffer, bufsize);
  11.         if (fmt) {
  12.                 fprintf(stderr, " " );
  13.                 va_start(ap, fmt);
  14.                 vfprintf(stderr, fmt, ap);
  15.                 va_end(ap);
  16.         }
  17.         ptr = (unsigned char*)pbuffer;
  18.         for (i = 0; i < bufsize; i++) {
  19.                 if ((i % 16) == 0) {
  20.                         fprintf(stderr, "\n0x%08x",i );
  21.                 }
  22.                 fprintf(stderr, " 0x%02x",ptr[i] );
  23.         }
  24.         fprintf(stderr, "\n");
  25.         fflush(stderr);
  26.         return;
  27. }

  28. #define DEBUG_BUFFER(ptr,size,...)  do{debug_buffer(__FILE__,__LINE__,ptr,size,__VA_ARGS__);}while(0)

  29. int simple_assertv(const char* file, int lineno, const char* resultstr, const char* fmt, va_list ap)
  30. {
  31.         va_list oldap;
  32.         char* fmtstr = NULL;
  33.         int fmtsize = 32;
  34.         int ret = 0;
  35.         memset(&oldap,0,sizeof(oldap));
  36.         memcpy(&oldap, ap, sizeof(oldap));
  37.         //DEBUG_BUFFER(&oldap,sizeof(oldap),"oldap pointer");
  38.         //DEBUG_BUFFER(ap,sizeof(oldap),"ap pointer");

  39.         fprintf(stderr, "fmt (%s)(", fmt);
  40.         vfprintf(stderr, fmt, ap);
  41.         fprintf(stderr, ")\n");
  42.         fflush(stderr);

  43. try_again:
  44.         memcpy(ap, &oldap, sizeof(oldap));
  45.         //DEBUG_BUFFER(ap,sizeof(oldap),"newap pointer");
  46.         if (fmtstr) {
  47.                 free(fmtstr);
  48.         }
  49.         fmtstr = NULL;
  50.         fmtstr = (char*)malloc(fmtsize);
  51.         if (fmtstr == NULL) {
  52.                 fprintf(stderr, "%s:%d can not alloc(%d)\n", file, lineno, fmtsize);
  53.                 abort();
  54.         }

  55.         ret = vsnprintf(fmtstr, fmtsize - 10, fmt, ap);
  56.         if (ret < 0 || ret >= (fmtsize - 10)) {
  57.                 fprintf(stderr, "expand size %d => %d\n", fmtsize, fmtsize << 1);
  58.                 fmtsize <<= 1;
  59.                 goto try_again;
  60.         }
  61.         va_end(ap);
  62.         ret = strcmp(resultstr, fmtstr);
  63.         if (ret != 0) {
  64.                 fprintf(stderr, "%s:%d (%s) != (%s)\n", file, lineno, resultstr, fmtstr);
  65.                 abort();
  66.         }

  67.         if (fmtstr) {
  68.                 free(fmtstr);
  69.         }
  70.         fmtstr = NULL;
  71.         fmtsize = 0;
  72.         return 0;
  73. }

  74. int simple_assert(const char* file, int lineno, const char* resultstr, const char* fmt, ...)
  75. {
  76.         va_list ap;
  77.         if (fmt) {
  78.                 va_start(ap, fmt);
  79.         }
  80.         //DEBUG_BUFFER(ap,sizeof(ap),"initliaze ap");
  81.         return simple_assertv(file, lineno, resultstr, fmt, ap);
  82. }

  83. #define SIMPLE_ASSERT(res,...) simple_assert(__FILE__,__LINE__,res,__VA_ARGS__)


  84. int main(void)
  85. {
  86.         SIMPLE_ASSERT("to display this help information", "%s %s", "to display", "this help information");
  87.         return 0;

  88. }
复制代码

回复 3# ljmmail

谢谢你的回复,你的方法是可以,但因为如果真的就是输入一个ap,那就需要保留这个值,我自己调整了一下,使用memcpy保留值,可以不改变参数输入的情况下,使代码不出现问题。

论坛徽章:
14
水瓶座
日期:2014-06-10 09:51:0215-16赛季CBA联赛之江苏
日期:2017-11-27 11:42:3515-16赛季CBA联赛之八一
日期:2017-04-12 14:26:2815-16赛季CBA联赛之吉林
日期:2016-08-20 10:43:1215-16赛季CBA联赛之广夏
日期:2016-06-23 09:53:58程序设计版块每日发帖之星
日期:2016-02-11 06:20:00程序设计版块每日发帖之星
日期:2016-02-09 06:20:0015-16赛季CBA联赛之上海
日期:2015-12-25 16:40:3515-16赛季CBA联赛之广夏
日期:2015-12-22 09:39:36程序设计版块每日发帖之星
日期:2015-08-24 06:20:002015亚冠之德黑兰石油
日期:2015-08-07 09:57:302015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2016-12-05 10:11 |只看该作者
回复 4# jeppeter

莫干傻事,好好用人家的接口
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP