问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

安全拷贝函数safe_memcpy实现分析

创作时间:
作者:
@小白创作中心

安全拷贝函数safe_memcpy实现分析

引用
CSDN
1.
https://blog.csdn.net/wangzhicheng1983/article/details/117366294

memcpy是C语言中常用的内存拷贝函数,但其存在缓冲区溢出和重叠拷贝等安全风险。本文将分析memcpy的缺陷,并介绍一个更安全的内存拷贝函数safe_memcpy的实现原理和使用方法。

一、memcpy缺陷分析

  1. memcpy原型:
#include <string.h>
void *memcpy(void *dest, const void *src, size_t n);
// 函数返回dest指针
  1. 缺陷分析:
    (1)memcpy容易发生缓冲区溢出,如果dest长度小于待拷贝的字节数n,那么程序将发生缓冲区溢出;
    (2)如果dest是高地址,src是低地址,拷贝可能发生错误,即源地址和目的地址重合部分在拷贝时被修改。

综上所述:memcpy参数较为简单,没有对程序安全性做进一步限制,将导致某些致命错误。

二、safe_memcpy实现分析

  1. 原型:
bool safe_memcpy(void *dst, const void *src, size_t len, const void *start, const void *end);
// dst指向目的地址
// src指向源地址
// len是待拷贝的字节数
// start指向目的地址开始地址
// end指向目的地址结束地址 即最后一个元素的后一个地址
  1. 实现分析:

safe_memcpy.hpp

#pragma once
#include <stdint.h>
#include <string.h>

static inline bool between(const uint8_t *start, const uint8_t *end, const uint8_t *p) {
    return (p < end) && (p >= start); // 注意是p < end不是p <= end
}

static inline bool safe_check(void *dst, size_t len, const void *start, const void *end) {
    if (len < 1) {
        return false;
    }
    if (!dst || !start || !end) {
        return false;
    }
    void *last_pos = ((uint8_t *)dst) + len - 1;
    if (last_pos < dst) {    // last_pos不能小于dst
        return false;
    }
    return between((uint8_t *)start, (uint8_t *)end, (uint8_t *)dst) &&     // dst在start与end之间
           between((uint8_t *)start, (uint8_t *)end, (uint8_t *)last_pos);  // last_pos即待拷贝区间最后元素地址也必须在start与end之间
}

static inline bool safe_memcpy(void *dst, const void *src, size_t len, const void *start, const void *end) {
    if (!safe_check(dst, len, start, end)) {
        return false;
    }
    if (!src) {
        return false;
    }
    memcpy(dst, src, len);
    return true;
}

(1)解决缓冲区溢出问题:调用safe_memcpy需要指定目的地址的开始和结束地址,safe_memcpy会检查目标空间是否能够容纳待拷贝字节数;
(2)解决低地址向高地址拷贝错误:如果源地址和目的地址部分区间重叠,通过指定start和end,safe_memcpy使用between((uint8_t *)start, (uint8_t *)end, (uint8_t *)last_pos)可以进行安全性判断。

  1. 测试:

test.cpp

#include <iostream>
#include "safe_memcpy.hpp"

int main() {
    char src[64] = "123";
    char dst[64] = "";
    safe_memcpy(dst, src, strlen(src), dst, dst + 64);
    std::cout << dst << std::endl;

    return 0;
}

代码仓库:https://github.com/wangzhicheng2013/safe_memcpy

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号