C安全问题与指针误用
欢迎关注我的个人博客:www.wuyudong.com, 更多精彩文章与您分享
指针的声明与初始化
1、不恰当的指针声明
考虑如下的声明:
int* ptr1, ptr2; // ptr1为指针,ptr2为整数
正确的写法如下:
int* ptr1, *ptr2;
用类型定义代替宏定义是一个好的习惯,类型定义允许编译器检查作用域规则,而宏定义不一定会。
使用宏定义辅助声明变量,如下所示:
#define PINT int*
PINT ptr1, ptr2;
不过结果和前面所说的一致,更好的方法是使用下面的类型定义:
typedef int* PINT;
PINT ptr1, ptr2;
2、使用指针未初始化
在使用指针之前未初始化会导致运行时错误,如下面的代码:
int* p;
...
printf("%d\n", *p);
指针p未被初始化,可能含有垃圾数据
3、处理未初始化指针
- 总是用NULL来初始化指针
- 用assert函数
- 用第三方工具
把指针初始化为NULL更容易检查是否使用正确,即便这样,检查空值也比较麻烦,如下所示:
int *pi = NULL;
...
if(pi == NULL) {
//不应该解引pi
} else {
//可以使用pi
}
我们可以使用assert函数来测试指针是否为空值:
assert(pi != NULL);
指针的使用问题
缓冲区溢出
缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量,使得溢出的数据覆盖在合法数据上,理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符,但是绝大多数程序都会假设数据长度总是与所分配的储存空间相匹配,这就为缓冲区溢出埋下隐患。操作系统所使用的缓冲区又被称为"堆栈".。在各个操作进程之间,指令会被临时储存在"堆栈"当中,"堆栈"也会出现缓冲区溢出。
下面几种情况可能导致缓冲区的溢出:
访问数组元素时没有检查索引值
对数组指针做指针算术运算时不够小心
用gets这样的函数从标准输入读取字符串
误用strcpy和strcat这样的函数
1、测试NULL
使用malloc这样的函数的时候一定要检查返回值,否则可能会导致程序的非正常终止,下面是一般的方法:
float *vector = malloc( * sizeof(float));
if(vector == NULL) {
//malloc分配内存失败
} else {
//处理vector
}
2、错误使用解引操作
声明和初始化指针的常用方法如下:
int num;
int *pi = #
下面是一种看似等价但是错误的声明方法:
int num;
int *pi;
*pi = #
3、迷途指针
参见《C迷途指针》
4、越过数组边界访问内存
没有什么可以阻止程序访问为数组分配的空间以外的内存,下面的例子中,我们声明并初始化了三个数组来说明这种行为:
#include<stdio.h>
int main()
{
char firstName[] = "";
char middleName[] = "";
char lastName[] = "";
middleName[-] = 'X';
middleName[] = 'X';
middleName[] = 'X';
printf("%p %s\n", firstName, firstName);
printf("%p %s\n", middleName, middleName);
printf("%p %s\n", lastName, lastName);
return ;
}
运行结果如下:

下图说明了内存分配情况:

5、错误计算数组长度
将数组传给函数时,一定要同时传递数组长度,这个信息帮助函数避免越过数组边界
#include<stdio.h>
void replace(char buffer[], char replacement, size_t size)
{
size_t count = ;
while(*buffer && count++ < size) {
*buffer = replacement;
buffer++;
}
}
int main()
{
char name[];
strcpy(name, "Alexander");
replace(name, '+', sizeof(name));
printf("%s\n", name);
return ;
}
6、错误使用sizeof操作符
其中一个例子是试图检查指针边界但方法错误
#include<stdio.h>
int main()
{
int buffer[];
int *pbuffer = buffer;
for(int i = ; i < sizeof(buffer); i++) {
*(pbuffer++) = ;
}
return ;
}
改为:i < sizeof(buffer) / sizeof(int);
7、有界指针
有界指针是指指针的使用被限制在有效的区域内,C没有对这类指针提供直接的支持,但是可以自己显示地确保。如下所示:
#define SIZE 32
char name[SIZE];
char *p = name;
if(name != NULL) {
if(p >= name && p < name + SIZE) {
//有效指针,继续
} else {
//无效指针,错误分支
}
}
一种有趣的变化是创建一个指针检验函数;
下面的代码定义一个函数消除无效指针:
int valid(void *ptr) {
return (ptr != NULL);
}
下面的代码依赖于_etext的地址,定义于很多的类linux操作系统,在windows上无效:
#include <stdio.h>
#include <stdlib.h> int valid(void *p) {
extern char _etext;
return (p != NULL) && ((char*) p > &_etext);
} int global; int main(void) {
int local; printf("pointer to local var valid? %d\n", valid(&local));
printf("pointer to static var valid? %d\n", valid(&global));
printf("pointer to function valid? %d\n", valid((void *)main)); int *p = (int *) malloc(sizeof(int));
printf("pointer to heap valid? %d\n", valid(p));
printf("pointer to end of allocated heap valid? %d\n", valid(++p));
free(--p);
printf("pointer to freed heap valid? %d\n", valid(p));
printf("null pointer valid? %d\n", valid(NULL)); return ;
}
在linux平台运行结果如下:
pointer to local var valid? 1pointer to static var valid? 1pointer to function valid? 0pointer to heap valid? 1pointer to end of allocated heap valid? 1pointer to freed heap valid? 1null pointer valid? 0C安全问题与指针误用的更多相关文章
- 《深入理解C指针》
<深入理解C指针> 基本信息 原书名:Understanding and using C pointers 作者: (美)Richard Reese 译者: 陈晓亮 丛书名: 图灵程序设计 ...
- 深入理解C指针----学习笔记
深入理解C指针 第1章 认识指针 理解指针的关键在于理解C程序如何管理内存,指针包含的就是内存地址. 1.1 指针和内存 C程序在编译后,以三种方式使用内存: 1. 静态. ...
- 部分博文目录索引(C语言+算法)
今天将本博客的部分文章建立一个索引,方便大家进行阅读,当然每一类别中的文章都会持续的添加和更新(PS:博文主要使用C语言) 博客地址:http://www.cnblogs.com/archimedes ...
- C++类型引用浅析
C++类型引用浅析 引言 从最早被Bjarne Stroustrup 发明,作为C语言的扩展,到广为人知C++98标准,再到最新的C++11.C++14和C++17标准,C++一直在不断地进步.演化. ...
- c/c++和java达到swap不同功能
首先我们来看看c/c++实施swap性能 void swap ( int & a, int & b) { int Temp; temp = a; a = b; b = temp; } ...
- 2 Java对象的创建过程
JAVA中创建对象直接new创建一个对象,对么对象的创建过程是怎样的呢? 程序运行过程中有许多的对象被创建出来.那么对象是如何创建的呢? 一 对象创建的步骤 1 遇到new指令时,检查这个指令的参数是 ...
- 面经 cisco
1. 优先级反转问题及解决方法 (1)什么是优先级反转 简单从字面上来说,就是低优先级的任务先于高优先级的任务执行了,优先级搞反了.那在什么情况下会生这种情况呢? 假设三个任务准备执行,A,B,C,优 ...
- javascript 误用this指针 的情况
理解了this指针后,我们再来看看一些很容易误用this指针的情况. 示例1——内联式绑定Dom元素的事件处理函数 <script type="text/javascript" ...
- C++智能指针简单剖析
导读 最近在补看<C++ Primer Plus>第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰,一解我以前的多处困惑.C++面试过程中,很多面试官都喜欢问智能指针相关的问题 ...
随机推荐
- 支付SDK的安全问题——隐式意图可导致钓鱼攻击
该漏洞涉及到app所使用的intent和intent filter. intent是一个可用于从一个app组件请求动作或处理事件的“消息对象”.Intent负责对应用中一次操作的动作.动作涉及数据. ...
- 【struts2】OGNL
1 OGNL概述 OGNL是对象图导航语言Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言(Expression Language,简称为EL),通 ...
- Angular开发Tips
1.在使用$routeProvider的时候,需要让模块依赖ngRoute,否则会提示找不到服务,示例: angular.module('module1', ['ngRoute']) .config( ...
- [Node.js] Node + Redis 实现分布式Session方案
原文地址: http://www.moye.me/?p=565 Session是什么? Session 是面向连接的状态信息,是对 Http 无状态协议的补充. Session 怎么工作? Sessi ...
- VirtualBox的网络设置(6种方式)
VirtualBox 可以为每一个虚拟机分配8个网卡.每一个网卡的连接方式可以选为下列之一: Not attached Network Address Translation (NAT) Bridge ...
- Android程序ToDoList增加配置项页面
本文要做的事情就是在前面做的简单的ToDoList程序上增加一个配置项页面(Reference).这个Reference页面也非常简单: 这个ToDoList现在有两个页面,主页面能填写待办事项,然后 ...
- BlocksKit初见:一个支持将delegate转换成block的Cocoa库
简介 项目主页: https://github.com/zwaldowski/BlocksKit BlocksKit 是一个开源的框架,对 Cocoa 进行了扩展,将许多需要通过 delegate 调 ...
- 用cryptico.js实现RSA加密(应对cryptico不支持PEM)
问题: 随手分享一下好了,这个问题困扰了很久. cryptico.js这个加密算法库很全,很适合在前端用到各种加密解密算法的需求.但是美中不足的是,它的RSA加密不支持PEM格式,所以如果你后端用ja ...
- 餐厅到店点餐系统(APP)
MY-HR 成员: 角色分配 学号 博客园 丘惠敏 PM项目经理 201406114203 http://www.cnblogs.com/qiuhuimin/ 郭明茵 用户 201406114204 ...
- "数学口袋精灵"bug(团队)
团队名:MY-HR 成员: 学号 博客园 团队贡献分 丘惠敏(组长) 201406114203 http://www.cnblogs.com/qiuhuimin/ 5 郭明茵 201406114204 ...