strncpy_s的正确打开方式

更新时间:2023-07-08 14:57:27 阅读: 评论:0

strncpy_s的正确打开⽅式
最近遇到了⼀个奔溃问题,程序在执⾏到某个点后,瞬间⼲⼲净净的退出,也没有dmp⽂件⽣成。这个奔溃在指定场景下出现,于是⽤Windbg执⾏程序,准备在奔溃点进⾏分析。
想法很好,但是在奔溃点,看不到堆栈信息。于是通过⽇志及问题出现场景,确定了怀疑点。但是在怀疑点,并没有看出问题。因为,我先⼊为主的以为,strncpy_s会做边界检测,不会越界访问及复制。
根据Windbg给出的诊断信息以及咨询同事,在TerminateProcess函数上加断点,运⾏程序,程序在TerminateProcess上中断下来,堆栈显⽰程序终⽌确实是由strncpy_s引起。
于是写了简单的Demo,进⾏问题分析及验证,堆栈如下:
Figure 1
问题出在strncpy_s上,奔溃原因是_invalid_parameter_noinfo函数中调⽤了TerminateProcess函数,看意思是参数有问题。
strncpy_s在C11引⼊,声明如下:
errno_t strncpy_s(char *restrict dest, rsize_t destsz,
const char *restrict src, rsize_t count)
其有如下特点:
1. As corrected by the post-C11 DR 468, strncpy_s, unlike strcpy_s, is only allowed to clobber the remainder of the
destination array if an error occurs.怎样快速记忆
2. Unlike strncpy, strncpy_s does not pad the destination array with zeroes, This is a common source of errors when
converting existing code to the bounds-checked version.
3. Although truncation to fit the destination buffer is a curity risk and therefore a runtime constraints violation for
strncpy_s, it is possible to get the truncating behavior by specifying count equal to the size of the destination array minus one: it will copy the first count bytes and append the null terminator as always: strncpy_s(dst, sizeof dst, src, (sizeof dst)-1)
⼤致意思如下:
1. 不像strcpy_s,strncpy_s只会在出错时,才会填充⽬标缓冲区中余下的区域
2. 不像strncpy,strncpy_s并不会将⽬标缓冲区填0,这是将当前代码转换到边界检查版本后常见的错误
二年级数学课本钟鼓楼刘心武3. 为了适应⽬标缓冲区⽽进⾏截断有安全风险,违反了strncpy_s的运⾏时约束,但可以通过指定源缓冲区待复制长度为⽬标缓冲区长
度减⼀来实现截断,这样,⽬标缓冲区会以’\0’结尾:strncpy_s(dst, sizeof dst, src, (sizeof dst)-1)
当前使⽤strncpy_s出现了奔溃,并且是因为参数问题,那就重点看下参数。简化后的⽰例源码如下:
int main()
{
char szDest[16] = {0};
char szSource[24] = "SourceSourceSource";
电脑下面任务栏没反应strncpy_s(szDest, sizeof(szDest), szSource, sizeof(szSource));没空造句
return 0;
}
⽬标缓冲区⼤⼩为16字节,源缓冲区⼤⼩为24字节。在使⽤strncpy_s时,待拷贝数据长度⼤于⽬标缓冲区⼤⼩。由于是参数错误,那应该是⽬标缓冲区太⼩的缘故了。
对于strncpy⽽⾔,如果⽬标缓冲区过⼩,复制依然会进⾏,如果没有访问不可访问内存,复制时不会发⽣什么问题。问题在于后续使⽤⽬标缓冲区时,在找’\0’结尾符时会出现问题,会出现神奇现象。同
时,由于strncpy可能会踩其他内存,导致案发现场离实际出问题点很远,定位问题很⿇烦,因为不知道具体哪⼀步踩了内存。
鉴于上述情况,有了strncpy_s函数,但是这个函数也不是银弹。它会做边界检测(根据⼊参),检测到异常时,直接抛出异常(Debug 下)或者程序直接终⽌(Relea下),因此案发现场就是出问题的地⽅,定位问题⽐较容易。但是,在Relea下,程序直接终⽌,转储⽂件中不⼀定会保持⾜够的⽤于定位问题的信息(甚⾄不⼀定会有转储⽂件,因为直接调⽤了TerminateProcess函数结束进程),这个时候,定位问题得⽤⼀些技巧,譬如直接打断点在TerminateProcess函数上。
知道了问题点,还是看看strncpy_s的实现,进⼀步了解这个函数。
Debug模式下, szDest缓冲区后⾯被填充了4个0xCC。
Figure 2
程序在执⾏到strncpy_s函数时,直接弹出提⽰框,这个提⽰框由断⾔引起,具体错误原因是:缓冲区太⼩。
Figure 3
根据堆栈,问题发⽣在common_tcsncpy_s函数中,这个函数被strncpy_s直接调⽤。
common_tcsncpy_s函数声明如下:
Figure 4
实现如下:
Figure 5
豆干炒肉
对于当前调试,问题出在_RETURN_BUFFER_TOO_SMALL这个宏上,宏已经说明了具体原因:缓冲区太⼩。
Figure 6
在返回之前,调⽤了_RESET_STRING函数。_RESET_STRING是宏,定义如下:#define _RESET_
STRING(_String, _Size) \
*(_String) = 0; \
dxf文件_FILL_STRING((_String), (_Size), 1);
/* string retting */
#define _FILL_STRING _SECURECRT__FILL_STRING
_SECURECRT__FILL_STRING宏定义如下:
Figure 7
土木工程主修课程
_SECURECRT_FILL_BUFFER_THRESHOLD 宏定义如下:

本文发布于:2023-07-08 14:57:27,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1073101.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:问题   函数   缓冲区   奔溃   出现   访问   复制
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图