昨天我在自制的"strcpy"功能上遇到了一些麻烦.虽然现在有效,但我有点困惑!
char* a = "Hello, World!"; //Works
char b[] = "Hello, World!"; //Works also
strcpy(a, "Hello!"); //Segmentation fault
strcpy(b, "Haha!!"); //Works..
Run Code Online (Sandbox Code Playgroud)
区别在哪里?为什么char指针会导致"分段错误"?
为什么这甚至有效?:
char* a = "Haha"; //works
a = "LOL"; //works..
Run Code Online (Sandbox Code Playgroud) 假设我有一些遗留代码是使用对C STL函数的不安全调用编写的strcpy.我们都知道这strcpy是不安全的,因为它使程序容易受到缓冲区溢出问题的影响.假设我要将所有调用替换为strcpy调用strncpy.一种用于替换所有技术调用strcpy(dest, src)将涉及调用strncpy与参数(dest, src, length of dest - 1),然后终止dest与\0.我知道这个问题是我们并不总是知道它的长度,dest因为它可能是指向堆上分配的内存的指针.
我们假设我可以计算出dest每个呼叫站点的长度.我可以取代所有调用strcpy与调用strncpy,这将保证我的计划是不受缓冲区溢出攻击(至少从使用不当的strcpy).但是,这种方法可能会以不合需要的方式默默地截断数据并改变程序行为.这比检测截断和中止程序更好吗?或者是允许截断还是记录它更好吗?
我是从有兴趣开发修补遗留代码的自动方法的人的角度问的.有没有人对如何最好地解决这个问题有任何想法?
我的理解如下:
char *指向一个字符串常量,修改它指向的数据是未定义的.但是,您可以更改指向的位置.
char[] 指内存块,您可以更改其内容但不能更改其内容.
strcpy(dest, src)复制src到dest.
我的问题是,这是不正确的使用strcpy()与dest作为一个char * 在已经指向的东西(我beleive旧的内容将被覆盖strcpy()-这是不确定的行为)?
例如:
char *dest = malloc(5);
dest = "FIVE";
char *src = malloc(5);
src = "NEW!";
strcpy(dest, src); /* Invalid because chars at dest are getting overwritten? */
Run Code Online (Sandbox Code Playgroud) 我正在为一个类编写C代码.这个类要求我们的代码在学校服务器上编译和运行,这是一个sparc solaris机器.我正在运行Linux x64.
我有这条线要解析(这不是实际的代码,但输入我的程序):
while ( cond1 ){
Run Code Online (Sandbox Code Playgroud)
我需要将"while"和"cond1"捕获到单独的字符串中.我一直在用strtok()这个.在Linux中,以下行:
char *cond = NULL;
cond = (char *)malloc(sizeof(char));
memset(cond, 0, sizeof(char));
strcpy(cond, strtok(NULL, ": \t\(){")); //already got the "while" out of the line
Run Code Online (Sandbox Code Playgroud)
将正确捕获字符串"cond1".然而,在solaris机器上运行它,给我字符串"cone1".
请注意,在我的程序中的许多其他情况下,字符串正在被正确复制.(例如,"while")被正确捕获.
有谁知道这里发生了什么?
我正在编写我的String类的版本,但Valgrind抱怨<<我的字符串操作符的实现.错误是在错误的行,如果我通过char打印char它工作得很好.
我哪里错了?
Valgrind错误:
== 2769 ==有条件的跳转或移动取决于未初始化的值(s)
== 2769 ==在0x4C2AC28:strlen(在/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so中)
== 2769 == by 0x4ECAD60:std :: basic_ostream>&std :: operator <<>(std :: basic_ostream>&,char const*)(在/usr/lib/x86_64-linux-gnu/libstdc++.so中. 6.0.17)
== 2769 == by 0x400BD5:operator <<(std :: ostream&,String&)(string.cpp:22)
== 2769 == by 0x400AAC:main(main.cpp:12)
我<<的字符串运算符:
ostream & operator << (ostream & o, String & inS) {
o << inS._pData << " "; // the wrong line
return o;
}
Run Code Online (Sandbox Code Playgroud)
我的String班级:
class String {
public:
unsigned _size;
char * _pData;
String(); …Run Code Online (Sandbox Code Playgroud) 我正在努力实现一些低级文件写入,其中文件格式具体到每一位。我需要将一个字符串从一个NSString长度为 16 的空终止字符串复制(根据 Xcode,这是不可分配的)。说到 ,我完全是个菜鸟c,并且想确保我正确理解这一点。这就是我目前正在做的事情:
//I have a non-null NSString called _friendly_name.
const char *string = [_friendly_name UTF8String];
//profile.friendly is a utf-8 null-terminated string
memcpy(&profile.friendly_name, &string, 16);
Run Code Online (Sandbox Code Playgroud)
这尚未经过测试,但我想确保这会起作用。这会提供我期望的行为吗?或者我应该以不同的方式复制字符串(例如strcpy)?
我正在尝试检查从stdin读取的行是否以"login:"开头,但strcmp似乎不起作用.
char s1[20], s2[20];
fgets(s1, 20, stdin);
strncpy(s2,s1,6);
strcmp(s2, "login:");
if( strcmp(s2, "login:") == 0)
printf("s2 = \"login:\"\n");
else
printf("s2 != \"login:\"\n");
Run Code Online (Sandbox Code Playgroud)
我不关心"login:"之后会发生什么,我只是想确定命令是如何给出的.我究竟做错了什么?
在我们公司的编码标准中禁止使用普通的旧 strcpy,因为它可能会导致缓冲区溢出。我正在寻找我们在代码中链接的某些 3rd Party Library 的来源。库源代码使用 strcpy 是这样的:
for (int i = 0; i < newArgc; i++)
{
newArgv[i] = new char[strlen(argv[i]) + 1];
strcpy(newArgv[i], argv[i]);
}
Run Code Online (Sandbox Code Playgroud)
由于在为要复制到的缓冲区分配内存时使用了 strlen,因此看起来不错。有没有可能有人可以利用这个正常的 strcpy ,或者这是否像我认为的那样安全?
我已经看到了导致缓冲区溢出情况的 strcpy 的幼稚使用,但这似乎没有,因为它总是使用 strlen 为缓冲区分配适量的空间,然后使用 argv[] 作为复制到该缓冲区源应始终为空终止。
老实说,我很好奇使用调试器运行此代码的人是否可以利用此功能,或者是否有任何其他策略试图破解我们的二进制文件(使用我们在其编译版本中链接的这个库源)可以用来利用此用途的strcpy。感谢您的投入和专业知识。
在Kees Cook 在 linux.conf.au 2019 发布的 YouTube 视频中,他提到strscpy自己是首选,但通常会做用户想要的事情(更少的NUL填充)。但是,他没有说明这个定义是什么(规范或标题),
从视频中滑出,
strscpy()我找不到man
$ for i in strcpy strlcpy strscpy; do man -w $i; done;
/usr/share/man/man3/strcpy.3.gz
/usr/share/man/man3/strlcpy.3bsd.gz
No manual entry for strscpy
Run Code Online (Sandbox Code Playgroud)