检测指针被意外写坏

目录

一 内存结构

二 取指针内容检测指针标记

三 封装实现及测试用例


     如果裸指针被意外写坏时(写内存写越界或者非法的类型转换后非法写入等错误代码)指针会指向非法内存,并且我们很难察觉也无法辨识该指针是否是一个有效的指针,当我们使用该指针是就会发生严重的问题甚至宕机,如何检测指针被意外写坏了呢,我们可以通过特殊的方式存储指针本身的值,并且给指针添加标记位如果被指针被写坏了,通过检测标记位来辨别指针是否被写坏。

一 内存结构

 假设指针32位(64系统下64位),用64位保存32位指针,上面第一排 高32位记为 hd,下面低32位记为ld

   白红色 :为指针的值,数字为31,30,………,00为指针的内存结构由高32位到低0位存储

  浅蓝色:指针flag,值可以任意填,图中全是1,白色部分默认是0,则上图64位数值为0Xaaaaaaaa55555555

0Xaaaaaaaa 二进制 10101010101010101010101010101010

0X55555555二进制 01010101010101010101010101010101

二 取指针内容检测指针标记

    获取指针内容:把图中钱蓝色变0然后上下两个32位整数求或运算结果为指针的值,p = (ld & 0Xaaaaaaaa) | (hd & 0x55555555)

  判断指针是否被写坏:((hd & 0Xaaaaaaaa) == 0Xaaaaaaaa) &&((ld &0x55555555 )== 0x55555555)

三 封装实现及测试用例

#include <cstddef>
#include <cstdio>
#include <stdexcept>
#include <sys/mman.h>
#include <cstring>
#include <signal.h>
#include <execinfo.h>
#include <sys/user.h>

#if defined(__x86_64__) || defined(WIN64)
#define SPO_MAGIC_NUM       0X8000000000000000
#define SPO_MAGIC_NUM_H     0X5555555555555555
#define SPO_MAGIC_NUM_L     0XAAAAAAAAAAAAAAAA
#define SPO_FLAG_H          (0XFFFFFFFFFFFFFFFF & SPO_MAGIC_NUM_L)
#define SPO_FLAG_L          (0XFFFFFFFFFFFFFFFF & SPO_MAGIC_NUM_H)
#define SPO_DATA_TYPE       unsigned long long
#define SPO_ERROR_MSG       "SafePointer<Tp> Is not valid,FLAGH = 0X%lx,FLAGL = 0X%lx,pointer = 0X%lx\n"
#endif

#if defined(__i386__) || defined(_WIN32)
#define SPO_MAGIC_NUM       0X80000000
#define SPO_MAGIC_NUM_H     0X55555555
#define SPO_MAGIC_NUM_L     0XAAAAAAAA
#define SPO_FLAG_H          (0XFFFFFFFF & SPO_MAGIC_NUM_L)
#define SPO_FLAG_L          (0XFFFFFFFF & SPO_MAGIC_NUM_H)
#define SPO_DATA_TYPE       unsigned long long
#define SPO_ERROR_MSG       "SafePointer<Tp> Is not valid,FLAGH = 0X%llx,FLAGL = 0X%llx,pointer = 0X%llx\n"

#endif


template<typename Tp>
class SafePointer
{
public:
    SafePointer() : nDataH(SPO_FLAG_H),nDataL(SPO_FLAG_L) {}
    SafePointer(Tp *pointer)
    {
        nDataH = SPO_FLAG_H;
        nDataL = SPO_FLAG_L;
        SPO_DATA_TYPE pvalue = (SPO_DATA_TYPE) pointer;
        int a = sizeof(void*);
        for (size_t index = 0; index < sizeof(void *) * 8;)
        {
            nDataL = nDataL | (pvalue & (SPO_MAGIC_NUM >> index)/*取出要保存的位,其他位置为*/);//保有当前位的值到相应位愿
            index++;
            nDataH = nDataH | (pvalue & (SPO_MAGIC_NUM >> index)/*取出要保存的位,其他位置为*/);//保有当前位的值到相应位愿
            index++;
        }
    }
    bool IsPointerBad()
    {
        char eMsg[256] = {0};
        printf("SafePointer<Tp> FLAGH = 0X%lx,FLAGL = 0X%lx\n",static_cast<unsigned long>(GetFlagH()), static_cast<unsigned long>(GetFlagL()));
        return  (GetFlagH() != SPO_FLAG_H || GetFlagL() != SPO_FLAG_L);
    }
    //获取高位fag
    SPO_DATA_TYPE GetFlagH() const { return nDataH & SPO_MAGIC_NUM_L; }
    SPO_DATA_TYPE GetFlagL() const { return nDataL & SPO_MAGIC_NUM_H; }
    inline Tp& operator*() const {return *GetThrow(); }
    inline Tp* operator->() const {return GetThrow(); }
private:
    Tp * GetThrow() const
    {
        Tp * pPoint = (Tp *) ((nDataL & SPO_MAGIC_NUM_L) | (nDataH & SPO_MAGIC_NUM_H));
        if (GetFlagH() != SPO_FLAG_H || GetFlagL() != SPO_FLAG_L)
        {
            char eMsg[256] = {0};
            sprintf(eMsg, SPO_ERROR_MSG, static_cast<unsigned long>(GetFlagH()), GetFlagL(), pPoint);
            throw  std::runtime_error(eMsg);
        }

        if (pPoint == NULL)
        {
            char eMsg[256] = {0};
            sprintf(eMsg,SPO_ERROR_MSG,GetFlagH(),GetFlagL(),pPoint);
            throw  std::runtime_error(eMsg);
        }
        return pPoint;
    }

private:
    SPO_DATA_TYPE nDataH;
    SPO_DATA_TYPE nDataL;
};

class Parent {};

class Boy : public Parent
{
public:
    Boy(int* pb_) : a(0),pb(pb_) {}
    int GetB() { return *pb;}
public:
    SafePointer<int> pb;
    char a;
};

class Girl : public Parent
{
public:
    Girl() : a(0){}
    void SetA(char a_)
    {
        a = a_;
    }
public:
    char a;
};


int main(int argc, char **argv)
{

    try
    {
        int *pint = new int;
        printf("Right pointer address = 0X%llx\n",pint);
        Parent* pPar = new Boy(pint);
        Girl* pGirl = (Girl*)pPar;
        pGirl->SetA(155);
        Boy* pBoy =(Boy*)pPar;
        pBoy->GetB();
        return 0;
    }catch (std::exception& e)
    {
        printf("Catch a exception,msg = %s\n",e.what());
    }

    SafePointer<Boy> pTmBoy= new Boy(new int);
    pTmBoy->GetB();
}

运行效果

 可以看到内存被意外写坏后排成功检测到病抛出异常。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值