# dmc **Repository Path**: hzc1998/dmc ## Basic Information - **Project Name**: dmc - **Description**: Dynamic Memory Check (DMC) , 解决C语言空指针、悬空指针、越界访问、野指针问题的一个方案。 - **Primary Language**: C - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2021-04-28 - **Last Updated**: 2021-11-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Dynamic Memory Check (DMC) 动态内存检测 动态内存检测,既在程序运行的时候检测内存的越界,野指针,空指针等问题,可以提高软件的安全性与稳定性。使用宏实现,所以对性能的消耗不大。能够解决rust解决了C语言的问题。 ## 使用守则 1. 所有属于DMC的内容都是以$符号开头的。 2. 每个DMA函数都只能写在单独的一行 3. DMA函数末尾可以不用加;分隔符 ## API主要分为3类 ### 一、基础型:处理内存分配与释放 * $define(type, name) 指针变量的定义,并初始化为NULL 例: ```c $define(char *, p) // 相当于char *p = NULL; ``` * $malloc(name, size) 为name指针分配新的内存空间,会检测name的值,如果name不是NULL则抛出提示。然后分配一个新的内存地址给name。 相当于name = malloc(size); 例: ```c $malloc(p, 32) // 为p分配一个32字节大小的内存 ``` * $free(name) 释放name指针的内存地址,首先会检测指针的值,如果为NULL则抛出提示,释放内存后会将指针置NULL,避免野指针问题。相当于free(name); 例: ```c $free(p) // 将p指向的地址释放 ``` ### 二、悬挂型:处理悬挂指针问题(返回了函数内部的局部变量) * $$ 表明需要对该函数进行悬挂指针检测,必须放在函数的开头,$$把\{符号替代了。 例: ```c char *test() $$ ... } ``` * $return(name) 返回name函数指针,并对它指针进行检测,如果是属于函数局部变量,则抛出错误。它需要和$$配合使用才行。相当于return name; 例: ```c char *test() $$ char tmp; $return(&tmp) // check dangling pointer bug } ``` ### 三、访问型:在边界内对指针进行读写访问,会对边界进行检测 * $read(name, max, idx, value) 读取name指针指向的区域,边界范围是[name, name + max),idx表明以索引方式要访问哪个成员,value保存结果。相当于value = name[idx]。 * $readptr(name, max, ptr, value) 读取name指针指向的区域,边界范围是[name, name + max),ptr表明以指针方式要访问哪个成员,value保存结果。相当于value = *ptr。 * $write(name, max, idx, value) 写入name指针指向的区域,边界范围是[name, name + max),idx表明以索引方式要访问哪个成员,value表明要写入的数据。相当于name[idx] = value。 * $writeptr(name, max, ptr, value) 写入name指针指向的区域,边界范围是[name, name + max),ptr表明以指针方式要访问哪个成员,value表明要写入的数据。相当于*ptr = value。 例: ```c #define BUFLEN 10 char buf[BUFLEN] = {0,1,2,3,4,5,6,7,8,9}; char data; $read(buf, BUFLEN, 0, data) // 读取buf[0]到data中 $readptr(buf, BUFLEN, &buf[1], data) // 读取buf[1]到data中 $read(buf, BUFLEN, 10, data) // 读取buf[10]到data中,访问越界,抛出错误 $readptr(buf, BUFLEN, &buf[11], data) // 读取buf[11]到data中,访问越界,抛出错误 $write(buf, BUFLEN, 10, data) // 写入data到buf[10]到data中,访问越界,抛出错误 $writeptr(buf, BUFLEN, &buf[11], 100) // 写入100到buf[11]中,访问越界,抛出错误 ``` #### 边界扩展接口bound * $bound(name, addr, size, count) 创建一个访问边界,name是边界的名字,addr是指针起始地址,size是单个成员的大小,count是成员的数量。 例: ```c $bound(buf_bound, buf, sizeof(char), 10) // 创建一个边界,名字为buf_bound,指针地址为buf,成员大小为char,数量为10 ``` * $get(name, idx, value) 从name边界中,读取一个索引为idx的数据到value中,相当于value = bound.addr[idx]。 * $getptr(name, ptr, value) 从name边界中,读取一个地址为ptr的数据到value中,相当于value = *ptr。 * $set(name, idx, value) 从name边界中,写入value到一个索引为idx的数据中,相当于bound.addr[idx] = value。 * $setptr(name, ptr, value) 从name边界中,写入value到一个地址为ptr的数据中,相当于*ptr = value。 例: ```c $bound(buf_bound, buf, sizeof(char), 10) char bound_value; $get(buf_bound, 0, bound_value) $get(buf_bound, 11, bound_value) // out of bound! $getptr(buf_bound, &buf[1], bound_value) $set(buf_bound, 20, 10) // out of bound! $set(buf_bound, 0, 10) $set(buf_bound, 8, bound_value) $setptr(buf_bound, &buf[7], bound_value) ``` 使用bound的好处是不用每次都写边界的大小和地址。 ## API简写 * $rd -> $read * $rdp -> $readptr * $wr -> $write * $wrp -> $writeptr * $ret -> $return * $def -> $define * $getp -> $getptr * $setp -> $setptr ## 联系方式 Email: 2323168280@qq.com