关闭

C语言开发中应该注意的一些问题

标签: c语言指针Klocwork
193人阅读 评论(0) 收藏 举报
分类:

       最近在使用Klocwork检查工具,着实发现了一些隐藏的问题,总体来说比pclint检查的更为细致。检查结果所暴露的一些问题,我觉得在开发阶段应该避免,这里面结合个人理解总结如下。权且当做C语言开发过程中需要注意的一些坑。

       1,文件关闭问题。很多时候在读文件的时候,会因为一些判断条件而提前退出文件读的过程,这个时候一定要注意关闭文件。其一是因为因为文件指针占用系统资源,对于io密集型的程序,文件指针的累计也是不可想象的。其二是因为因为文件指针不同于普通的指针,确切的说文件指针应该叫做文件结构体指针,也就是说其指向的是文件结构体的内存。像fseek,fgetc等使文件指针发生偏移的函数,其实改变的是这个文件指针所指向内存结构体中的某个值。因此这个指针如果不关闭,再次使用的时候难免发生错误。

       2,指针判空,通常来说写程序的时候指针判空是最常见的判断条件,但是往往在使用C语言库函数,例如strstr这种返回值为指针的情形,会忘记判为空。那么将其返回值传入memset中自然会可能出现错误。

       3,局部变量初始化。但是我觉的这也是很重要的一点。首先,因为局部变量是动态的分配内存,存放在栈区,如果不初始化,其初始值是随机的,也就是说,指针将是野指针,变量将是随机变量。那么如果不小心使用了,或者在赋值的时候,只赋值了该变量的部分区域(这个问题详见这篇文章,或者像2中提到的判断没初始化的局部指针(一般是不为空的),那么将导致错误。将局部变量初始化为0,局部指针初始化为NULL都是通常的选择。其次我们在写代码的时候都是万般小心,各种测试和走查。但是仍有一些隐藏的错误会合入到版本中,在后续的修改中,需要消除其中的一些隐患的时候。我们改代码的状态和写代码的时候将完全不同,至少很难全局把握整个程序。那么这个时候,如果我们前期的一些工作,例如局部变量初始化这些细节做好,将是非常重要的。另外,在改代码的过程中,往往会直接使用数字,魔术字也就这样产生了。

       4,数组越界问题。这个问题可以归结为指针访问越界问题,因为数组名就是指针地址,但是,当字符串数组和字符串指针在一起比较的时候还是会有一定的差异,后续会提到。导致数组越界或者指针的非法访问原因有很多,这里面以C语言的库函数使用为例加以说明。函数strncpy和strcpy,正常对于字符串拷贝函数而言,一般建议使用strncpy,因为strncpy明确了从源地址项目的地址拷贝字符串的字节大小。使用strcpy(dst,src),如果strlen(src)=10,而dst合法的取地址范围为0-5,那么必然造成访问越界的情况,无论dst是数组还是指针。像类似问题还有sprintf以及snprintf函数,正常都是建议使用带能够确定字符串长度的函数来进行字符串函数的操作。

       5,C语言库函数隐藏问题。在使用C语言库函数的时候务必要确保对该函数有比较充分的了解。举个例子sprintf以及snprintf函数,这两个函数,前面已经提到,建议使用snprintf。他们的作用就是格式化字符,由于其都是变参函数,因此snprintf能够很好的确保格式化之后拷贝多少个字节到目标地址中,从这个方面讲sprintf是不安全的。另外一个需要注意的问题在于这个函数原型为int snprintf(char*str, size_t size,const char*format, ...);,其目标地址为char*也就是字符串,而C语言的字符串是以\0结尾的,因此snprintf在格式化之后的拷会带上一个\0,因此size的大小应该是拷贝字符串的长度+1,那么要确保的是str的合法访问地址范围,则要保证其地址访问空间大于等于size。这个是kw在检查过程中暴露将这个问题暴露出来(但是其推理逻辑很难懂,我花了很长时间才意识到是字符串末尾添加\0的原因)。因此我猜想kw对于诸如strcpy以及sprintf等存在安全问题的函数都是加入黑名单的。

       前面提到sprintf在做格式化之后的拷贝时候,总是在目标字符串末尾添加\0,但是4中所提到的库函数char *strncpy(char *dst, const char *src, size_t n);却并不总是在目标字符串末尾添加\0,其在n小于等于src长度时候,目标末尾不会添加\0。由此可见C语言不同的库函数,出发点还是不一样的,作为使用者,要尤为关注这一点,应为这往往会导致core dump。

       其实这还让我想到一个问题就是,新技术的更新问题,正常来说stnrcpy以及snprintf这些安全的函数已经存在好多年,包括我在内仍然有很多人去使用不安全strcpy以及sprintf,不经历一些坑,也体会不到痛。

       经过上述的分析,我在想,对于C语言而言,什么是字符串。通常可能就是认为由字符和数字等组成的一串东东,但是站在内存的角度而言,字符串其实是从起始地址到\0的一段内存偏移。当然对于数组而言,因为数组有确定的大小,不必在结尾加上\0表示字符串的结束,但是对于指针而言,要想确定该字符指针的合法访问地址,那么使用\0就是一个必要选项,使用\0来区分不同内存的边界。因此C语言中所有涉及到字符串操作的函数,我觉得要十分的警惕,应为\0的存在是访问越界的重要因素。

       本文为CSDN村中少年原创文章,转载记得加上小尾巴偶,博主链接这里

2
1

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:61995次
    • 积分:1117
    • 等级:
    • 排名:千里之外
    • 原创:49篇
    • 转载:0篇
    • 译文:0篇
    • 评论:32条
    感谢打赏 微信二维码
    微信