尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
realloc 失败时原指针仍然有效:`p = realloc(p, n)` 这一行漏掉了一个临时变量
本文首发于 CSDN。结论都能用手册原文核对代码可以照着跑。一段跑了两年的日志采集程序某天被投诉「偶尔丢日志」。不是全丢是每次 OOM 前后丢掉最后几行。查了两天。程序的写法是这样的char*bufmalloc(1024);size_tcap1024;/* ... 读数据满了就扩容 ... */bufrealloc(buf,cap*2);cap*2;strcpy(bufused,line);重试逻辑对扩容逻辑对读逻辑也对。问题在那句赋值上realloc失败时返回NULL赋回buf之后原来那块内存的地址就丢了——既没释放也再也拿不到。紧接着strcpy往NULL上写程序崩在无关的地方而崩之前那几行日志已经写进「丢失的旧块」里。手册对失败的定义比大多数人以为的严格realloc的 RETURN VALUE 有一句话很多人从没读到那一行If these functions fail, the original block is left untouched; it is not freed or moved.失败时原块保持不变既不释放也不移动。这句话反过来读就是失败之后你还持有原指针它仍然有效你可以继续用它或者主动free掉。丢失地址不是realloc干的是那句赋值干的。正确的写法只有一个形状——先收进临时变量void*tmprealloc(buf,cap*2);if(tmpNULL){/* 原块还在buf 仍可用这里决定是退出还是保留旧容量 */free(buf);return-1;}buftmp;cap*2;还有三个附带结论同样写在手册里第一realloc可能搬家。the returned pointer may be the same as p if the allocation was not moved … or different from p if the allocation was moved to a new address.所以任何缓存了旧指针的地方链表节点、外部结构体、别的线程在realloc之后都必须更新否则就是悬垂指针。第二realloc(p, 0)在 glibc 上是个坑。手册的 BUGS 一节写得很直接The glibc implementation of realloc() is not consistent with that, and as a consequence, it is dangerous to call realloc(p, 0) in glibc.给出的绕法也很简单realloc(p, size ? size : 1)。真要释放就直接free别用realloc(p, 0)表达「缩到零」。第三reallocarray能挡住乘法溢出。手册对malloc(n * size)这种写法明确提了If the multiplication of n and size would result in integer overflow, then calloc() returns an error. By contrast, an integer overflow would not be detected in the following call to malloc()reallocarray(p, n, size)做的就是把这道检查加上。扩容逻辑里凡是「元素个数 × 元素大小」的乘法都该用它。为什么这个 bug 只在 OOM 时出现因为它需要一个「分配失败」的条件才会触发。条件触发概率现象机器内存充足几乎为零完全正常测试环境永远看不到容器内存接近上限低偶发崩溃日志里最后几条丢失开了 overcommit更低realloc返回非空真正写的时候才 OOMKill有RLIMIT_AS限制中可稳定复现但需要专门构造最后一行值得多说。手册 NOTE 里写了 Linux 默认的乐观分配策略when malloc() returns non-NULL there is no guarantee that the memory really is available也就是说realloc返回非空不代表内存真的到手了。这条会让「用返回值判断是否 OOM」的思路在高负载下失效进程可能直接被 OOM killer 干掉连失败分支都走不到。真正可控的复现方式是用setrlimit设一个RLIMIT_AS上限把分配压到失败。我们后来把它写进了单测每个扩容点都跑一次「限制到刚好不够」的用例。换成预分配加分段能省掉什么如果逻辑允许把「反复扩容」换成「按块分配 块指针数组」就不需要realloc了structchunk{char*p;size_tlen;};staticstructchunkchunks[64];/* 每块固定 64KB满了就开下一块永不 realloc */代价是读取时要跨块拼接收益是没有搬家、没有失败分支、没有悬垂指针。日志采集这种「只追加、不随机访问」的场景分段几乎总是更省心。顺带说两句工具valgrind能查泄漏但查不出「丢了指针」——因为那块内存在进程退出时还在只是没人引用。-fsanitizeaddress能抓住「往 NULL 上写」这个后果但抓不住根因。真正能抓住根因的是代码审查规则凡是对realloc的返回值直接赋给原指针的写法一律标记为可疑。这条规则执行下来我们代码库里同类写法清掉了十七处。这类基础题我先按手册条目编号把草稿归档归档表用 AI墨衍 维护再在 CSDN 上写成文章会员的发文额度够我一口气把一批草稿都存下来GEO 检测能看出文章在 AI 搜索里有没有被引用图文同步则省掉了每个平台重排一遍的时间https://mp.csdn.net/vip?utm_sourceITmoyan常见问题Qrealloc失败之后直接free(buf)对吗对。原块还在free它会正常释放。前提是这句赋值没发生——一旦buf NULL就没有块可释放了。Qrealloc(NULL, n)等价于malloc(n)吗等价。手册原文「If p is NULL, then the call is equivalent to malloc(size)」。Q缩小容量会不会失败一般不会但可能发生搬家。缩小也可能返回新地址所以临时变量的写法对缩小同样适用。Qcalloc和malloc哪个更适合数组calloc。它在乘法溢出时返回错误而malloc(n * size)不检查溢出calloc还顺手把内存清零。Q为什么我的程序在realloc之后指针值变了但数据没丢因为数据被拷到了新地址。realloc保证「从块首到新旧尺寸较小者」的内容不变但新地址需要重新取旧地址立即失效。Q容器里 C 程序的 OOM 是什么表现多数情况是被 cgroup 直接 OOMKill进程收不到NULL也就走不到失败分支。这时候看dmesg比看日志有用。写在最后这次修复只改了一行搬移但引出一个更值得记住的判断库里返回NULL的失败往往不是「什么都发生了」而是「什么都没发生」。realloc失败时什么都没发生是你自己的赋值把它变成了「发生了」。我后来把这批分配函数的「失败后的正确动作」整理成了一张表散在几个项目的编码规范里底稿是用 AI墨衍 把手册条目按「操作 / 失败后指针是否有效 / 该做什么」三列排出来的几份文档之间同步一次就够。查表比凭记忆稳。想要把发文额度、GEO 检测、图文同步一起用起来的话入口在这里https://mp.csdn.net/vip?utm_sourceITmoyan
RELATED

相关推荐

Java三国杀源码解析:从环境搭建到技能扩展的实战指南

Java三国杀源码解析:从环境搭建到技能扩展的实战指南

简介:这是一份基于Java语言实现的三国杀游戏项目源文件,面向对卡牌游戏开发、Java面向对象编程及游戏逻辑实现感兴趣的开发者与学习者。项目Alpha 0.5.11版本已基本实现标准版25个武将、104张牌的全部技能,将复杂的桌面游戏规则抽象为可执行的…

📅 2026/10/30 13:13:14
YOLOX+ByteTrack在OpenCV+ONNX Runtime部署避坑指南

YOLOX+ByteTrack在OpenCV+ONNX Runtime部署避坑指南

简介:本资源是一套面向计算机视觉开发者与算法工程师的端到端目标跟踪实践方案,聚焦YOLOX检测与ByteTrack跟踪在OpenCVONNXRuntime框架下的跨语言部署。资源提供C与Python双版本完整实现,覆盖模型加载、预处理、推理、后处理及多目标关联全流…

📅 2026/10/30 13:13:14
OpenCV 4.8.0 Windows 编译指南:带人脸识别模块的完整教程

OpenCV 4.8.0 Windows 编译指南:带人脸识别模块的完整教程

简介:这份资源是面向Windows平台C与计算机视觉开发者的OpenCV 4.8.0完整编译包,基于VS2022(VC17)x64环境构建,同时整合了官方安装包中缺失的opencv_contrib模块,可直接调用人脸识别等机器学习功能&#xff…

📅 2026/10/30 13:08:13
MORE NEWS

更多资讯

📰

超级具身智能“感知-决策中枢”研究(12):基于FRA架构的语义总线与动态适配层

前沿技术探索:FRA核心定义与设计理念 FRA(Factorized Robotic Agent, FRA,亦称:因式分解机器人智能体)是一套因式化数实融合一体化新型智能系统,核心设计理念是全链路系统解耦,将机器人作业的感知、推理、动作执行三大核心能力拆解为独立平行子模块,整合为统一、闭环、…

📰

4.10 Canvas 组件实现自由绘图

微信小程序 Canvas 组件实现自由绘图一、案例介绍本次案例使用微信小程序 type"2d" 的 Canvas 组件,实现手写涂鸦画板。基础功能支持手指触摸滑动绘制线条、一键清空画布;扩展功能新增按钮,循环切换画笔线条颜色。适合学习小程序 C…

📰

大模型推理优化全解:KV Cache、PagedAttention、连续批处理与投机解码

大模型推理优化全解:KV Cache、PagedAttention、连续批处理与投机解码 一、一个真实的"为什么这么慢" 搭了个大模型服务,用户一上来就问:"你为什么这么慢?"盯着屏幕看推理时间——7 秒一个 token。回头一看配…

📰

让员工的浏览器“只干该干的事“:企业浏览器管控四道防线

摘要:浏览器是企业 IT 管控的薄弱环节——员工随意安装浏览器、访问高风险站点、私装扩展、修改设置,网关方案管不到浏览器内部。本文基于 Endpoint Central 的浏览器安全能力,提出"入口审批 → 网站锁定 → 风险隔离 → 新旧兼容"…

📰

Agentic AI 框架选型指南:OpenAI Agents SDK 与主流框架对比

Agentic AI 框架选型指南:OpenAI Agents SDK 与主流框架对比 一、选框架之前,先立坐标系 如果你要在这一周给产品加一个能自主干活的 AI,大概率会在多个 Agentic AI 框架之间反复横跳。但"框架好不好"没法直接比,得先有…

📰

Windows 64位 ImageJ 安装包选型:Java 与插件配置全攻略

简介:面向Windows 64位系统的Fiji/ImageJ集成安装包,适合生物医学成像、物理学、工程学及材料分析等科研场景,解决图像查看、测量、滤波与批量处理需求。压缩包约320MB,内含Fiji.app自包含目录,解压后双击启动脚本即可…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬