memcpy参数顺序写反会导致向只读内存或非法地址写入,触发Invalid write或SIGSEGV;重叠拷贝则被valgrind标记为潜在错误,应改用memmove。

memcpy(dst, src, n) 顺序写反会触发什么错误
直接报 Invalid write of size X 或 SIGSEGV,但不是因为函数本身错,而是你把源地址当目标、目标当源,导致往只读内存(如代码段、常量区)或空指针、非法地址写数据。Memcheck 不会主动提示“参数顺序反了”,它只忠实地报告:你在往一个不该写的地址上写了。
常见现象:
- 程序在 memcpy 后立刻崩溃,gdb 回溯停在
__memcpy_avx_unaligned或类似汇编入口 - valgrind 日志里出现
Address 0x... is not stack'd, malloc'd or free'd,且写操作(write)发生在 dst 参数位置 - 如果 dst 是 const 字符串字面量(如
"hello"),会明确报Permission denied类似提示
用 valgrind 捕获 memcpy 重叠问题(src 和 dst 重叠)
标准 memcpy 不保证处理重叠内存,用错了会静默损坏数据——valgrind 的 Memcheck 能抓到这个行为。
它检测到重叠时,会输出类似:
==12345== Source and destination overlap in memcpy(0x... /* dst */, 0x... /* src */, 100) ==12345== at 0x4C37F8E: memcpy (vg_replace_strmem.c:1021)
注意:这不是 fatal error,但会标记为「潜在错误」。如果你确实需要重叠拷贝,应改用 memmove。
实操建议:
- 搜索代码中所有
memcpy调用,检查 dst 和 src 是否来自同一块 buffer(比如memcpy(buf+1, buf, len)) - 对疑似重叠场景,用
memmove替换,无需改逻辑 - 加断言辅助验证:
assert(dst + n (仅调试构建启用)
排查 memcpy 崩溃时,必须确认的三件事
段错误不等于 memcpy 有 bug,而是它暴露了上游内存管理问题。重点不是“怎么调 memcpy”,而是“谁给的地址不可靠”。
请立即检查:
-
src是否为nullptr?是否来自已释放的cv::Mat::data(ROS 场景高频雷区)? -
dst是否指向只读内存?是否是栈上小数组但n过大导致越界? -
n是否为负数或极大值?Memcheck 会报Invalid read/write of size ...,但源头常是计算n的表达式溢出或符号误用(比如用int存 size_t 差值)
别急着改 memcpy 行,先在调用前加日志:printf("memcpy %p ,再配合 valgrind 定位哪一端失效。
valgrind 运行命令要带 -g 和 --track-origins=yes
没调试符号,valgrind 只能告诉你错在 memcpy 内部;没开启 origin tracking,它甚至不会告诉你未初始化值从哪来——而这恰恰是很多 src 为空的根本原因(比如局部指针未初始化就传入)。
正确启动方式:
valgrind --tool=memcheck \ --leak-check=full \ --track-origins=yes \ --show-leak-kinds=all \ --log-file=valgrind.log \ ./your_program
关键点:
- 编译必须带
-g(否则行号全丢) -
--track-origins=yes会让 valgrind 多花 2–3 倍时间,但能定位到char* p;这种未赋值就用的源头 - 不要省略
--leak-check=full:内存泄漏常和悬垂指针共存,泄漏的 buffer 被复用后就成野指针
最易被忽略的是:ROS 中 cv::Mat 数据可能绑定到 ROS 消息生命周期,processed_image.data 在 fillImage 返回后就失效——这个坑不在 memcpy 参数本身,而在你传进去的那个指针,早就不是你的了。


















