bug
VS2015环境下,显示strcpy()函数出错的解决办法: This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. 即使前面加了头函数文件cstring 也无济于事。
原因:vs准备弃用strcpy的,安全性较低,所以微软提供了strcpy_s来代替.如果继续使用strcpy的,那么只需要在函数体前面加上#pragma warning(disable:4996)就可以了。
strcpy_s(dest, bufsize, src);
bufsize为dest缓冲区最大长度。它与 strcpy 的不同在于,在它取得额外参数来决定目的缓冲区大小时,会因为发生溢位而出现错误,如此一来,就可以预防缓冲区溢位。
PS: 缓冲区溢位攻击
当前存入的数据量大于缓冲区的容量,可能导致栈帧指向原本的函数返回地址被覆盖,黑客利用一点,篡改进程运行时栈(比如指向shell脚本),从而改变程序的正常流向。
写出线程安全的strcpy()
线程安全:当多个线程访问某个方法时,不管你通过怎样的调用方式、或者说这些线程如何交替地执行,我们在主程序中不需要去做任何的同步,这个方法的结果行为都是我们设想的正确行为,那么我们就可以说这个方法是线程安全的。
参考:https://www.cnblogs.com/chenyg32/p/3739564.html
设计:
1,参数校验
2,链式编程
1 |
|
假如考虑dst和src内存重叠的情况,需要考虑直接按内存一位一位进行复制。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38//解决dest与src内存重叠, cnt = 复制个数
char * my_memcpy(char * dest, const char * src, int cnt) {
// 空指针的检查
//宏 : 计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。
assert(src != nullptr && dest != nullptr);
char * ret = dest;
//内存覆盖:src<=dst<=src+strlen(src)
if (dest >= src && dest <= src + cnt - 1) {
//从高地址开始复制
dest = dest + cnt - 1;
src = src + cnt - 1;
while (cnt--)
*dest-- = *src--;
}
else {
//内存无覆盖,从低地址开始复制
while(cnt--)
*dest++ = *src++;
}
// 返回原始dest的值
return ret;
}
char * my_strcpy2(char * dest, const char * src) {
// 空指针的检查
assert(src != nullptr && dest != nullptr);
char * ret = dest;
//strlen仅仅计算字符个数,不包括最后的\0。
my_memcpy(dest, src, strlen(src) + 1);
// 返回原始dest的值
return ret;
}
内存覆盖时为什么要从高地址开始复制,往低地址走:
eg:
1 | *s = "abc"; |