当前位置:首页 > 芯闻号 > 充电吧
[导读] 1. gets()函数Q:下面的代码中隐含着安全问题,能发现吗? 1 #include 2 int main(void) 3 { 4   char buff[10]; 5   mems

1. gets()函数
Q:下面的代码中隐含着安全问题,能发现吗?

 1 #include
 2 int main(void)
 3 {
 4   char buff[10];
 5   memset(buff,0,sizeof(buff));
 6 
 7   gets(buff);
 8 
 9   printf("n The buffer entered is [%s]n",buff);
10 
11   return 0;
12 }

 

A:问题在于gets()函数,这个函数是接收标准输入的一串字符串,并且没有检查字符串缓冲区的大小就
直接拷贝到buff数组中,这可能导致在写入buff内存时溢出,可以使用fgets()函数代替这个函数,

char *fgets( char *str,int n,FILE *stream );

 

2.strcpy()函数
Q:下面代码是一个密码验证的过程,是否可以在不知道密码的情况下验证通过

 1 #include
 2 #include 
 3 
 4 int main(int argc, char *argv[])
 5 {
 6 
 7   char passwd[10];
 8   int flag = 0;
 9   memset(passwd,0,sizeof(passwd));
10 
11   strcpy(passwd, argv[1]);
12 
13   if(0 == strcmp("LinuxGeek", passwd))
14   {
15     flag = 1;
16   }
17 
18   if(flag)
19   {
20     printf("n Password cracked n");
21   }
22   else
23   {
24     printf("n Incorrect passwd n");
25 
26   }
27   return 0;
28  }

 

A:strcpy()函数没有验证输入的字符串长度,所有在执行时可能出现写内存出现溢出,这很危险,如这代码,
flag是初始化为0的,当内存溢出时可能会写到flag内存中,这会使得flag内存不为0,即使不执行if语句的
比较flag也为真,所以就相当于密码正确

如: $ ./psswd aaaaaaaaaaaaa 输出: Password cracked

可以使用strncpy()函数代替
现在编译器也发现这种情况,所以在为程序分配内存时是分散的分配内存,如果要看到上面执行的情况,使用gcc的话
可以使用 ‘-fno-stack-protector’参数(我没验证)

3.main()函数的返回类型
Q:下面代码是否能编译通过?是否还存在其他问题

 1 #include
 2 
 3 void main(void)
 4 {
 5   char *ptr = (char*)malloc(10);
 6 
 7   if(NULL == ptr)
 8   {
 9     printf("n Malloc failed n");
10     return;
11   }
12   else
13   {
14     // Do some processing
15 
16     free(ptr);
17   }
18 
19   return;
20 }

A:对于现在的编译器这段代码是可以编译通过的,不过是会有警告,main()返回类型最好使用int类型,
当一个函数执行结束时最后返回一个状态值,现在C/C++返回一个0值表示程序正常退出,否则有异常.

4.内存泄露
Q:下面代码执行结果会出现内存泄露吗?

 1 #include
 2 
 3 void main(void)
 4 {
 5   char *ptr = (char*)malloc(10);
 6 
 7   if(NULL == ptr)
 8   {
 9     printf("n Malloc failed n");
10     return;
11   }
12   else
13   {
14     // Do some processing
15   }
16 
17   return;
18 }

A:其实内存泄露是个很严重的问题,其实上面代码执行结果不会出现内存泄露,虽然没有使用free()
回收内存,但是当程序执行结束后程序里分配的内存会自动释放,如果是分配的内存放到一个死循环里
就会出现严重的内存泄露,或者程序一直执行着,动态分配的内存会一直占有着无法释放.
有篇文章介绍了内存泄露的检测方法:http://www.cnblogs.com/skynet/archive/2011/02/20/1959162.html

5.free()函数
Q:下面代码执行时输入如 ‘freeze’会崩溃但输入如t ‘zebra’就不会为什么?

 1 #include
 2 
 3 int main(int argc, char *argv[])
 4 {
 5     char *ptr = (char*)malloc(10);
 6 
 7     if(NULL == ptr)
 8     {
 9         printf("n Malloc failed n");
10         return -1;
11     }
12     else if(argc == 1)
13     {
14         printf("n Usage  n");
15     }
16     else
17     {
18         memset(ptr, 0, 10);
19 
20         strncpy(ptr, argv[1], 9);
21 
22         while(*ptr != 'z')
23         {
24             if(*ptr == '')
25                 break;
26             else
27                 ptr++;
28         }
29 
30         if(*ptr == 'z')
31         {
32             printf("n String contains 'z'n");
33             // Do some more processing
34         }
35 
36        free(ptr);
37     }
38 
39     return 0;
40 }

A:这个问题主要是指针移到的问题,当输入如‘zebra’这样的字符串('z'开头)时,ptr指针没有移到,所以
ptr指针指向的内存还是malloc分配的原内存的起始地址,但是输入‘freeze’时,ptr指针移到了,已经不是指向原来
分配的内存的起始地址了,所有free时就会出错

题外话:在实现如strcpy的函数时,如下

 1 char *strcpy(char *strDest, const char *strSrc)
 2 {
 3     assert((strDest != NULL) && (strSrc != NULL));
 4     
 5     if(strDest == strSrc)
 6     return strDest; //注意这个.. 
 7 
 8     char *pstr = strDest; //保存原始地址
 9     while((*strDest++ = *strSrc++) != '');
10     return pstr;
11 }

定义了一个指针pstr保存了原始地址,然后再执行移到操作,结束后再返回写入的原始地址以便进行链式操作,
我实现这个函数的时候就是出现了一个很二的错误,就是移到操作后直接返回strDest指针,现在的strDest指针
已经移到字符串末尾了,如果那样的话要释放strDest内存就会出错了

6.atexit和_exit
Q:下面代码中,atexit()函数没有被调用,why?

 1 #include
 2 void func(void)
 3 {
 4     printf("n Cleanup function called n");
 5     return;
 6 }
 7 
 8 int main(void)
 9 {
10     int i = 0;
11 
12     atexit(func);
13 
14     for(;i<0xffffff;i++);
15 
16     _exit(0);
17 }

A:主要是因为_exit()函数,这个函数是直接终止程序,没有调用一些如atexit()的清理函数,要想调用
atexit()函数,就需要调用exit()函数或者return返回操作退出程序.

MSDN给出了exit()和_exit()函数的区别

The exit and _exit functions terminate the calling process. exit calls, in last-in-first-out (LIFO) order,
the functions registered by
atexit and _onexit, then flushes all file buffers before terminating the process. _exit terminates the process without processing atexit or _onexit or flushing stream buffers. The status value is typically set to 0 to indicate a normal exit and set to some other value to indicate an error

7.void* 和 C 结构体
Q:能否设计一个函数能够接受任何类型的参数? 也可以传递多个参数给这个函数?
A:

int func(void *ptr);

传递的时候需要强制转换为void*类型,到函数内以后再强制转换回来,如果要传多个参数,可以定义一个
结构体,将要传递的参数放到结构体里,定义一个结构体对象,对成员赋值后,将对象传给函数.
注:我不知道在哪里看到有人说C/C++是不安全的语言,因为可以类型强制转换,但在这里发现强制转换
带来的好处.


8. * 和 ++ 操作
Q:下面的代码输出的结果是什么? and Why?

 1 #include
 2 
 3 int main(void)
 4 {
 5     char *ptr = "Linux";
 6     printf("n [%c] n",*ptr++);
 7     printf("n [%c] n",*ptr);
 8 
 9     return 0;
10 }

A:输入的结果:
[L]
[i]
Why? 这个涉及到*号和++的优先级问题,*和++的优先级是一样的,编译器在识别时是先右后左,
所有先检测到++后到*,不过++是在ptr后面,所以自加在*ptr后执行,输出L,然后移动到i处,下
一条语句执行的时候输出i.
原作者给出来的解释我不太理解
(ptr++ is evaluated first and then *ptr. So both these operations result in ‘L’),
为什么说两个操作结果都是'L'???

9.改变代码区(只读区)
Q:下面代码为什么会崩溃?

 1 #include
 2 
 3 int main(void)
 4 {
 5     char *ptr = "Linux";
 6     *ptr = 'T';
 7 
 8     printf("n [%s] n", ptr);
 9 
10     return 0;
11 }

A:因为 *ptr = 'T' 操作尝试改变在代码区的 "Linux"的字符串,这是不合法的,其实如果要改变的话
可以先动态分配一块内存(在堆区),然后再Copy "Linux"到这块内存中,可以就可以执行*ptr = 'T'操作

10.程序改变自己的名字
Q:如何实现一个程序在运行的时候改变自己的名字
A:这个需要知道main()函数的两个参数的意义了

 1 #include
 2 #include 
 3 int main(int argc, char *argv[])
 4 {
 5     int i = 0;
 6     char buff[100];
 7 
 8     memset(buff,0,sizeof(buff));
 9 
10     strncpy(buff, argv[0], sizeof(buff));
11     memset(argv[0],0,strlen(buff));
12 
13     strncpy(argv[0], "NewName", 7);
14 
15     // Simulate a wait. Check the process
16     // name at this point.
17     for(;i<0xffffffff;i++);
18 
19     return 0;
20 }

main()函数的argc表示的是传进来的参数个数,argv[]保存的是参数的内容,但是
argv[0]保存的是程序自己名字

11.返回局部变量地址
Q:下面的代码是否存在问题?如果有的话那如何修改?

 1 #include
 2 
 3 int* inc(int val)
 4 {
 5   int a = val;
 6   a++;
 7   return &a;
 8 }
 9 
10 int main(void)
11 {
12     int a = 10;
13 
14     int *val = inc(a);
15 
16     printf("n Incremented value is equal to [%d] n", *val);
17 
18     return 0;
19 }

A:问题是返回了一个局部变量的地址,a的作用域只在inc()函数中,函数结束后a的内存会释放,如果使用
一个已经被释放了的内存相当危险,解决方法可以传给inc()函数的参数修改为传地址或者引用(C++)
不使用值传递,int* inc(int *val)或者int* inc(int &val)

12.printf()函数参数的执行
Q:代码的输出结果是什么?

 1 #include
 2 
 3 int main(void)
 4 {
 5     int a = 10, b = 20, c = 30;
 6 
 7     printf("n %d..%d..%d n", a+b+c, (b = b*2), (c = c*2));
 8 
 9     return 0;
10 }

A:输出的结果为
110..40..60
函数的参数是从右到左执行的,但是打印是从左到右的

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
换一批
延伸阅读

特朗普集团近日取消了其新推出的T1智能手机“将在美国制造”的宣传标语,此举源于外界对这款手机能否以当前定价在美国本土生产的质疑。

关键字: 特朗普 苹果 AI

美国总统特朗普在公开场合表示,他已要求苹果公司CEO蒂姆·库克停止在印度建厂,矛头直指该公司生产多元化的计划。

关键字: 特朗普 苹果 AI

4月10日消息,据媒体报道,美国总统特朗普宣布,美国对部分贸易伙伴暂停90天执行新关税政策,同时对中国的关税提高到125%,该消息公布后苹果股价飙升了15%。这次反弹使苹果市值增加了4000多亿美元,目前苹果市值接近3万...

关键字: 特朗普 AI 人工智能 特斯拉

3月25日消息,据报道,当地时间3月20日,美国总统特朗普在社交媒体平台“真实社交”上发文写道:“那些被抓到破坏特斯拉的人,将有很大可能被判入狱长达20年,这包括资助(破坏特斯拉汽车)者,我们正在寻找你。”

关键字: 特朗普 AI 人工智能 特斯拉

1月22日消息,刚刚,新任美国总统特朗普放出重磅消息,将全力支持美国AI发展。

关键字: 特朗普 AI 人工智能

特朗普先生有两件事一定会载入史册,一个是筑墙,一个是挖坑。在美墨边境筑墙的口号确保边境安全,降低因非法移民引起的犯罪率过高问题;在中美科技产业之间挖坑的口号也是安全,美国企业不得使用对美国国家安全构成威胁的电信设备,总统...

关键字: 特朗普 孤立主义 科技产业

据路透社1月17日消息显示,知情人士透露,特朗普已通知英特尔、铠侠在内的几家华为供应商,将要撤销其对华为的出货的部分许可证,同时将拒绝其他数十个向华为供货的申请。据透露,共有4家公司的8份许可被撤销。另外,相关公司收到撤...

关键字: 华为 芯片 特朗普

曾在2018年时被美国总统特朗普称作“世界第八奇迹”的富士康集团在美国威斯康星州投资建设的LCD显示屏工厂项目,如今却因为富士康将项目大幅缩水并拒绝签订新的合同而陷入了僵局。这也导致富士康无法从当地政府那里获得约40亿美...

关键字: 特朗普 富士康

今年5月,因自己发布的推文被贴上“无确凿依据”标签而与推特发生激烈争执后,美国总统特朗普签署了一项行政令,下令要求重审《通信规范法》第230条。

关键字: 谷歌 facebook 特朗普

众所周知,寄往白宫的所有邮件在到达白宫之前都会在他地进行分类和筛选。9月19日,根据美国相关执法官员的通报,本周早些时候,执法人员截获了一个寄给特朗普总统的包裹,该包裹内包含蓖麻毒蛋白。

关键字: 美国 白宫 特朗普
关闭