您好,欢迎访问三七文档
如下代码存在什么样的漏洞?1.#defineKSIZE10242.charkbuf[KSIZE]3.intcopy_from_kenel(void*user_dest,intmaxlen)4.{5.intlen;6.len=KSIZEmaxlen?KSIZE:maxlen;7.memcpy(user_dest,kbuf,len);8.}原理分析:表头文件:#includestring.h定义函数:void*memcpy(void*dest,constvoid*src,size_tn)函数说明:memcpy()用来拷贝src所指的内存内容前n个字节到dest所指的内存地址上。memcpy的长度参数n的类型是size_t,即unsignedint型。int的最高位是符号位,unsignedint的最高位是有效位。当maxlen为负数时,len值也为负数,所以隐式类型转换成size_t后会是一个很大的值,结果导致memcpy极出现越界。在进入函数时做入参检查可以有效的避免此类错误。实验结果:2•int*p1,*p2;•intvalue;•p1=(int*)0x500;•p2=(int*)0x508;•value=p2-p1;•问:value的值?原理分析:指针的减法运算的意义是两个指针之间的元素的数目,指针运算会自动考虑它所指向的对象的长度。(0x508-0x500)/(sizeof(int))实验结果:3•inta[5]={0x01,0x2,0x3,0x4,0x5};•int*ptr;•ptr=(int*)(&a+1);•printf(%x,%x,*(a+1),*(ptr));•问:打印的两个值相等吗?为什么?原理分析:a+1是a[1]的地址,所以*(a+1)是a[1]的值0x2。&a+1是a[5]的地址,已经越界,所以*(ptr)打印的是野值。所以两个值应该是不相等的。实验结果:4以下两个程序有问题吗?正确的为什么正确,错误的为什么错误?•程序一:•char*get_str(void)•{•charstr[]={abcd};•returnstr;•}•intmain(intargc,char*argv[])•{•char*p=get_str();•printf(%s\n,p);•return0;•}•程序二:•char*get_str(void)•{•char*str={abcd};•returnstr;•}•intmain(intargc,char*argv[])•{•char*p=get_str();•printf(%s\n,p);•return0;•}原理分析:charstr[]={abcd};属于栈区空间在,.stack段,这是由编译器自动分配和释放的区域。主要存储函数的参数,函数的局部变量等。当一个函数开始执行时,该函数所需的实参,局部变量就推入栈中,该函数执行完毕后,之前进入栈中的参数和变量等也都出栈被释放掉。str指向的是一块已释放的地址空间。char*str={abcd};属于字符常量空间,在.text段,不会被释放,程序结束后由系统释放。实验结果:5•inta[][3]={1,2,3,4,5,6};•int(*ptr)[3]=a;•printf(%d%d,(*ptr)[1],(*ptr)[2]);•++ptr;•printf(%d%d,(*ptr)[1],(*ptr)[2]);•这段程序的输出是:•(a)2356•(b)2345•(c)4500•(d)以上均不对原理分析:int(*ptr)[3]是一个数组指针,指针指向的是一个含有三个元素的一维数组。Ptr,(*ptr)[1]是取ptr指针的第二个元素即2,(*ptr)[2])是取ptr指针的第三个元素即3。prt+1=base+3*sizeof(int),Ptr,(*ptr)[1]是取ptr指针的第二个元素即5,(*ptr)[2])是取ptr指针的第三个元素即6。实验结果:6说出下列函数的输出•voidmain()•{•charx[]=string;•printf(%d\n,sizeof(x));•}原理分析:执行charx[]=string语句后,x实际存储是□s□t□r□i□n□g□\0,sizeof(数组名)计算的是该数组占用的空间大小,所以sizeof(x)=7。实验结果:7该段代码的主要问题是什么?•x_type*entry;•structlist_head*pos;•list_for_each(pos,head){•entry=list_entry(pos,x_type,lst);•list_del(&entry-lst);•free((void*)entry);•}原理分析:list_for_each的定义如下:#definelist_for_each(pos,head)\for(pos=(head)-next;pos!=(head);\pos=pos-next)list_del的定义如下:staticinlinevoid__list_del(structlist_head*prev,structlist_head*next){next-prev=prev;prev-next=next;}staticinlinevoidlist_del(structlist_head*entry){__list_del(entry-prev,entry-next);}如果在list_for_each遍历过程中使用list_del,list_del后pos的next和prev都已经变为NULL,pos=pos-next运行时就会异常访问。list_for_each_safe函数首先将pos的后指针缓存到n,处理一个流程后再赋回pos,避免了这种情况的发生。因此只遍历链表不删除节点时可以使用前者,若有删除节点的操作,则要使用后者。list_for_each_safe的定义如下:#definelist_for_each_safe(pos,n,head)\for(pos=(head)-next,n=pos-next;pos!=(head);\pos=n,n=pos-next)实验结果:(1)用list_for_each(2)用list_for_each_safe8C++的注释风格是//,在C语言中也可以用,那么:•inta,b,c;•b=8;•c=2;•a=b//*;•//*/c;问:a的值是多少?为什么?原理分析:预处理器会删除从“//”开始到后面碰到的第一个换行符之间的所有内容。实验结果:编辑工具显示是注释,因为语句结束符;被//注释掉了,所以a=b语句缺少结束符实验的结果显示编辑有错误9问:n的值是多少?•intfoo(inta[10])•{•intb[20];•intn=sizeof(b)/sizeof(a);•}原理分析:C语言会自动地将作为参数的数组声明转换为相应的指针声明。在这种情况下intfoo(inta[10]);与intfoo(inta[]);和intfoo(int*a);是等价的,此时a就是一个指针,不是数组名,编译器实际处理的时候也当指针来处理,所以sizeof(a)是指针的大小4。sizeof(b)是数组b占的空间大小,即20*sizeof(int)=20*4。所以sizeof(b)/sizeof(a)=20。实验结果:10•voidfunc1()•{•chara[]=192.168.0.1;•char*p=192.168.0.1;•}•1)执行++操作,哪个正确?•(A)++a;(B)++p;•2)执行赋值,是哪个正确?•(A)a[1]='2';(B)*p='2';•为什么?原理分析:数组名是数组的首地址,就是数组中第一个元素的地址,是常量,其值是不能修改的,因此不能进行类似改变其值的操作。所以(A)++a;错误指针是一个特殊的变量,里面存储的数值被解释成为内存里的一个地址。其值是可变的,++p相当于p所指向的内存区移动了一个sizeof(char)个字节。所以(B)++p;正确chara[]=192.168.0.1;a[]是一个字符数组,编译器首先在栈中分配一定的连续空间用于存放192.168.0.1中的字符以及结尾符,然后把字符串常量的内容,复制到这个栈中的连续空间中。str是数组名,用来表示这个连续空间的起始地址,str中存放的是栈地址,这个地址的数据是可写的。所以(A)a[1]='2';正确char*p=192.168.0.1;语句中192.168.0.1字符串常量是存放于只读数据区的,所以p存放的是一个只读数据区的地址,而对只读区的数据进行写操作是禁止的,所以(B)*p='2';错误实验结果:
本文标题:c语言题
链接地址:https://www.777doc.com/doc-7028925 .html