设为首页 加入收藏

TOP

C基础 内存越界和内存监测的简单处理(一)
2017-10-12 17:41:11 】 浏览:1799
Tags:基础 内存 越界 监测 简单 处理

引言

  突然感觉要出去走走了, 醒了后 刷完牙就在联系coding, 不知不觉到了 黄昏.

看看天, 打开灯. 又感觉到了 夜夜夜夜 .

13年到北京务工, 遇到一批批NB的同龄人物. 一块工作, 一块喜欢锻炼, 一块默默的学习.

从他(她)们身上发现一个事实.

假如我们一样聪明,

  当你抱怨自己为什么努力了, 确还是 这么水的时候  ;   其实他(她)们在拼命. 而你只是在努力 ,

假如我们不一样聪明,

  如果还不能开挂,  那会是怎么样精彩 x x x x.

 

前言  -  内存越界处理

我们先看设计图. 内存越界检查原理如下

上面原理是不是很简单. 而这恰恰是最通用的做法. 美的东西不负责.  美很重要.

那我们按照上面设计思路. 首先构建 接口文件 checkmem.h

#ifndef _H_MEMCHECK_CHECKMEM
#define _H_MEMCHECK_CHECKMEM

#include <stddef.h>

/*
* 对malloc进行的封装, 添加了边界检测内存块
* (inline 原本分_DEBUG有宏处理, 后面没加等于没用)
* sz        : 申请内存长度
*            : 返回得到的内存首地址
*/
extern inline void* mc_malloc(size_t sz);

/*
 * 对calloc进行封装, 添加边界检测内存块
 * cut        : 申请的个数
 * sz        : 每个的大小
 */
extern inline void* mc_calloc(size_t cut, size_t sz);

/*
* 对relloc进行了封装, 同样添加了边间检测内存块
*/
extern inline void* mc_realloc(void* ptr, size_t sz);

/*
* 对内存检测, 看是否出错, 出错直接打印错误信息
* 只能检测, check_* 得到的内存
*/
extern inline void mc_check(void* ptr);

#endif // !_H_MEMCHECK_CHECKMEM

 主要是对 malloc, calloc, realloc 进行添加尾部和头部的内存块处理. 就这么简单一步. 假如能看懂上面设计思路图.

这些代码都可以跳过了.   思路比代码重要.  好那我们继续展现实现部分. checkmem.c

#include "checkmem.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

// 控制台打印错误信息, fmt必须是双引号括起来的宏
#define CERR(fmt, ...) \
    fprintf(stderr,"[%s:%s:%d][error %d:%s]" fmt "\r\n",\
         __FILE__, __func__, __LINE__, errno, strerror(errno), ##__VA_ARGS__)
//控制台打印错误信息并退出, t同样fmt必须是 ""括起来的字符串常量
#define CERR_EXIT(fmt,...) \
    CERR(fmt,##__VA_ARGS__),exit(EXIT_FAILURE)

// 插入字节块的个数
#define _INT_CHECK        (1<<4)

/*
* 对malloc进行的封装, 添加了边界检测内存块
* sz        : 申请内存长度
*            : 返回得到的内存首地址
*/
inline void* 
mc_malloc(size_t sz) {
    // 头和尾都加内存检测块, 默认0x00
    char* ptr = calloc(1, sz + 2 * _INT_CHECK);
    if (NULL == ptr) {
        CERR_EXIT("malloc sz + sizeof struct check is error!");
    }

    //前四个字节保存 最后一个内存块地址 大小
    size_t* iptr = (size_t*)ptr;
    *iptr = sz + _INT_CHECK;

    return ptr + _INT_CHECK;
}

/*
* 对calloc进行封装, 添加边界检测内存块
* cut        : 申请的个数
* sz        : 每个的大小
*/
inline void* 
mc_calloc(size_t cut, size_t sz) {
    return mc_malloc(cut*sz);
}

/*
* 对relloc进行了封装, 同样添加了边间检测内存块
*/
inline void* 
mc_realloc(void* ptr, size_t sz) {
    // 先检测一下内存
    mc_check(ptr);

    // 重新申请内存
    char* cptr = (char*)ptr - _INT_CHECK;
    char* nptr = calloc(1, sz + 2 * _INT_CHECK);
    if (NULL == nptr) {
        CERR_EXIT("realloc is error:%p.", ptr);
    }
    // 内存移动
    size_t* bsz = (size_t*)cptr;
    memcpy(nptr, cptr, *bsz < sz ? *bsz : sz);
    *bsz = sz;
    
    free(cptr);
    return nptr;
}

// 检测内存是否错误, 错误返回 true, 在控制台打印信息
static void _iserror(char* s, char* e) {
    while (s < e) {
        if (*s) {
            CERR_EXIT("Need to debug test!!! ptr is : (%p, %p).check is %d!",s, e, *s);
        }
        ++s;
    }
}

/*
* 对内存检测, 看是否出错, 出错直接打印错误信息
* 只能检测, check_* 得到的内存
*/
inline void 
mc_check(void* ptr) {
    char *sptr = (char*)ptr - _INT_CHECK;

    //先检测头部
    char* s = sptr + sizeof(size_t);
    char* e = sptr + _INT_CHECK;
    _iserror(s, e);

    //后检测尾部
    size_t sz = *(size_t*)sptr;
    s = sptr + sz;
    e = s + _INT_CHECK;
    _iserror(s, e);
}

代码实现都很中规中矩, 比较容易. 也就百行. 按照接口文件一个个看实现. 很容易学到开发中技巧. 提高实战技巧.

扯一点, C, C++ 老开发人员水平都比较高, 不喜欢写注释. 这个强烈推荐不是大牛的选手一定要多写注释.

不要扯 什么  <代码即注释> . 多写注释容易加深自己二次思考, 加快自己的成长. 不要和老开发人学这个 , 如果你跳槽, 遇到一个大项

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇使用C语言将pcm数据封装成wav文件.. 下一篇338. Counting Bits

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目