BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #72999同步于 2013/8/3
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

va_start和vsprintf告警指针越界

bingyi
2013/8/3镜像同步12 回复
如上题所述,为什么用va_start和vsprintf会告警可能指针越界?然后换成vsnprintf,用VC编译会说无法识别,是为什么?
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
tonyjansan机器人#1 · 2013/8/3
change vsnprintf to _vsnprintf 【 在 bingyi 的大作中提到: 】 : 如上题所述,为什么用va_start和vsprintf会告警可能指针越界?然后换成vsnprintf,用VC编译会说无法识别,是为什么?
bingyi机器人#2 · 2013/8/3
在问下,有va_starts这种用法吗? 【 在 tonyjansan 的大作中提到: 】 : change : vsnprintf : to : ...................
iFadeToBlack机器人#3 · 2013/8/3
没有 【 在 bingyi 的大作中提到: 】 : 在问下,有va_starts这种用法吗?
bingyi机器人#4 · 2013/8/3
好吧,这是我自创的,现在出问题了 【 在 iFadeToBlack 的大作中提到: 】 : 没有 :
eussac机器人#5 · 2013/8/4
【 在 bingyi 的大作中提到: 】 : 如上题所述,为什么用va_start和vsprintf会告警可能指针越界?然后换成vsnprintf,用VC编译会说无法识别,是为什么? 这个和sprintf会导致拼装越界是一个原理。当然,即使使用snprintf也只能保证单次安全,连续拼装还是可能越界的。 我这儿用的都是自己封装的拼装函数,在snprintf的基础上多一个入参的检查。
bingyi机器人#6 · 2013/8/4
能跟我详细说说吗?什么样的入参检查?一般va_start不都是两个参数吗?现在总说va_start的第二个参数可能会指针越界 【 在 eussac 的大作中提到: 】 : 这个和sprintf会导致拼装越界是一个原理。当然,即使使用snprintf也只能保证单次安全,连续拼装还是可能越界的。 : 我这儿用的都是自己封装的拼装函数,在snprintf的基础上多一个入参的检查。
tonyjansan机器人#7 · 2013/8/7
看看va_start的实现你就懂了: /* * Use local definitions of C library macros and functions * NOTE: The function implementations may not be as efficient * as an inline or assembly code implementation provided by a * native C library. */ #ifndef va_arg #ifndef _VALIST #define _VALIST typedef char *va_list; #endif /* _VALIST */ /* * Storage alignment properties */ #define _AUPBND (sizeof (acpi_native_int) - 1) #define _ADNBND (sizeof (acpi_native_int) - 1) /* * Variable argument list macro definitions */ #define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd))) #define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND)))) #define va_end(ap) (void) 0 #define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND)))) #endif /* va_arg */ 其中va_start传入参数ap,宏将其指向定位到格式化串的第一个变长参数位置,但如果此时函数体本身未传入任何参数,则访问越界,输出内容不可控。 举例: printf("%d\n"); 【 在 bingyi 的大作中提到: 】 : 能跟我详细说说吗?什么样的入参检查?一般va_start不都是两个参数吗?现在总说va_start的第二个参数可能会指针越界
bingyi机器人#8 · 2013/8/7
什么意思?就是说我在编译va_start所在函数时,函数还未被调用?这种情况如何解决呢?更改函数位置?但是有时候函数是被其他文件中的函数调用,我怎么才能控制va_start所在函数的调用呢? 【 在 tonyjansan 的大作中提到: 】 : 看看va_start的实现你就懂了: : [code=c] : /* : ...................
tonyjansan机器人#9 · 2013/8/7
【 在 bingyi 的大作中提到: 】 : 什么意思?就是说我在编译va_start所在函数时,函数还未被调用?这种情况如何解决呢?更改函数位置?但是有时候函数是被其他文件中的函数调用,我怎么才能控制va_start所在函数的调用呢? 你在说什么我已经读不懂了...别乱,举个具体的例子来逐行捋捋: // int MyPrintf(const char* format, ...) { // ...的内容是可变参数列表 va_list ap; // 指向可变参数列表的指针 char buf[512]; // 存放可变参数转化成的格式化字符串数组 int result; // 返回值变量 va_start(ap, format); // 将第一个可变参数的地址赋给ap,即ap指向可变参数列表(...)的开始 result = vsprintf(buf, format, ap); // 将参数ap和format进行转化形成格式化字符串, // 即生成最终输出的字符串 va_end(ap); // 将ap复位 if (result >= 0) printf(buf); return result; } 如果你的format和可变参数(...)是一一对应的话不会出现问题,但如果你如下调用MyPrintf的话就会有问题: MyPrintf("%d\n"); // 调用1 MyPrintf("%d%d\n", 1); // 调用2 调用1: 你会发现确实ap被指向了format参数的后边,但是format后边你并未传递其它参数进来,所以ap指向了一片不可控的内存(越界操作),而format中却有一个%d取代符,于是在buf里就变成了一个不可测的值输出出来了。 调用2: ap确是指向了第一个也是唯一一个可变参数1,但是在vsprintf(buf, format, ap);时会发现,format中有两个%d取代符,可传进来的可变参数却只有1个,于是在取代第2个%d时,ap又指向了一片不可控内存,造成越界操作。