C++安全编码:变量

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/uestcyms/article/details/88195971

变量

指针变量、表示资源描述符的变量、BOOL变量声明必须赋予初值

为了贯彻零开销原则(C++之父Bjarne在设计C++语言时所遵循的原则之一,“无须为未使用的东西付出代价”),编译器一般不会对一般变量进行初始化,也包含指针,所以负责初始化指针变量的只有程序员自己。

使用未初始化的指针时,非常危险,因为指针指向内存空间,所以程序员容易通过未初始化的指针改写该指针随机指向的存储区域,而由此产生的后果是不确定的

全局变量和静态变量的默认值是0,局部变量的默认值不确定。

由于局部变量的默认值都是不确定的:使用随机指针,后果不确定(往往比较严重)、bool变量导致分支错误、资源描述符导致操作文件异常;
相关网址介绍:
C/C++中已初始化/未初始化全局/静态/局部变量/常量在内存中的位置
c++堆、栈、局部变量、全局变量

指向资源句柄或描述符的变量,在资源释放后立即赋予新值

资源释放后,对应的变量应该立即赋予新值,防止后续又被重新引用。例外:如果释放语句刚好在变量作用域的最后一行,可以不进行赋值。

有如下好处

  • 双重释放指针时避免崩溃。(释放空指针不会引起错误)
  • 避免重用已释放的指针。(如果是赋值为空,只是将重复使用这种错误行为转换为崩溃或者隐藏了起来。这个做法其实有些争议,因为一旦隐藏了起来,出现问题后,很难进行debug。)
unsigned char *msg = NULL;
free(msg);
msg = (unsigned char *)malloc(...); //msg变量又被赋予新值,推荐做法。

类的成员变量必须在构造函数赋予初值

如果类中声明了变量,则必须在构造函数中对变量进行赋值。
和第一条相同,因为零开销原则,对象(类的实例)中的变量也不一定会初始化。

// safedemo.h
/**********************************************************************
      >File Name:     savedemo.h
      >Author:        sunrise
      >Mail:          [email protected]
      >Created Time:  Mon 04 Mar 2019 08:12:07 AM EST
*************************************************************/

#include<iostream>
using namespace std;

#ifndef SAVEDEMO_H
#define SAVEDEMO_H
class SaveDemo{
public:
    SaveDemo();
    int testNumber;
};
#endif

// savedemo.cpp
/**********************************************************************
      >File Name:     savedemo.cpp
      >Author:        sunrise
      >Mail:          [email protected]
      >Created Time:  Mon 04 Mar 2019 08:14:34 AM EST
*************************************************************/

#include<iostream>
#include "savedemo.h"
using namespace std;

SaveDemo::SaveDemo(){

}

// main.cpp
/**********************************************************************
      >File Name:     main.cpp
      >Author:        sunrise
      >Mail:          [email protected]
      >Created Time:  Thu 28 Feb 2019 02:16:11 AM EST
*************************************************************/
#include<iostream>
#include "savedemo.h"
using namespace std;

SaveDemo savedemoA;

int main(){
    SaveDemo savedemoB;

    cout << "SaveDemoA: " << savedemoA.testNumber << endl;
    cout << "SaveDemoB: " << savedemoB.testNumber << endl;

    return 0;
}

输出结果:

SaveDemoA: 0
SaveDemoB: 4197200

说明当对象是局部变量时(处于栈空间),则是不确定的值;全局变量是全部初始化为0。

严禁对指针变量进行sizeof操作

编码人员往往由于粗心,将指针当做数组进行sizeof操作,导致实际的执行结果与预期不符。也就是防止在讨论数组的时候,对指针使用sizeof

char *buffer = (char *)malloc(size);
char path[MAX_PATH] = {0};
... ...
memset(path, 0, sizeof(path));
memset(buffer, 0, sizeof(buffer));//将内存大小误写了sizeof,与预期不符。

如果判断当前的指针类型大小,请使用sizeof(char *)的方式。

Do not apply the sizeof operator to a pointer when taking the size of an array

尽量使用const

在变量声明前加const关键字,表示变量不可被修改,这样就可以利用编译器进行类型检查,将代码的权限降到更低。

你可以通过它来指定一个语义上的约束(一个特定的不能够更改的对象)这一约束由编译器来保证。通过一个const,你可以告诉编译器和其他程序员,你的程序中有一个数值需要保持恒定不变。不管何时,当你需要这样一个数时,你都应该这样做,这样你便可以让编译器来协助你确保这一约束不被破坏。

全局变量的访问如果涉及多个线程,需要考虑多线程竞争条件问题

应该尽量减少全局变量的使用,多个线程访问到该全局变量时,则访问过程中必须加锁。

同一个函数内,局部变量所占用的空间不要过大

程序在运行期间,函数内的局部变量保存在栈中,栈的大小是有限的。如果申请过大的静态数组,可能导致出现运
行出错。 建议在申请静态数组的时候,大小不超过0x1000。 下面的代码,buff申请过大,导致栈空间不够,程序
发生stackoverflow异常。

#define MAX_BUFF 0x1000000
int Foo()
{
      char buff[MAX_BUFF] = {0};
      ...
}

猜你喜欢

转载自blog.csdn.net/uestcyms/article/details/88195971
今日推荐