中望软件-实习总结

中望软件-实习总结
小米里的大麦实习总结
2026.07.23 – 2026.09.28,在广州中望龙腾软件(ZWSOFT)的软件框架小组待了三个月。这是我第二段实习,也是目前为止最"深"的一段 —— 前面那两个月像在不停地拆各种炸弹,这三个月则是一头扎进 1,591 万行 C++ 的商业代码里,写属于自己的静态分析规则。这篇是对这三个月的一个整理,也方便以后翻看。
1. 基本信息
| 项目 | 内容 |
|---|---|
| 实习单位 | 广州中望龙腾软件股份有限公司(ZWSOFT) |
| 所属部门 | 共性技术研究院 / 共性组件研发部 / 综合软件技术组 / 软件框架小组 |
| 实习时间 | 2026 年 7 月 23 日 – 2026 年 9 月 28 日(约 3 个月) |
| 实习地点 | 上海 |
| 岗位方向 | 软件开发实习生 |
| 参与产品 | ZW3D 悟空 2027(集成 CAD · CAE · CAM · PDM 的商业 CAD/CAM 软件) |
工作重心大致分三块:模块依赖可视化看板约 45%,Clang 静态分析规则集约 45%,剩下的约 10% 花在扫描工具链的接手与共同维护上。
2. 这段日子在做什么
1. 先认识一下 ZW3D:一个 86GB 的庞然大物
入职第一天,HR 小姐姐带着我把公司各个部门走了一遍,部门领导叶博士又带着我和每一位同事相互认识,然后我就被拉去开组会了。第一次经历这么专业、正式的场景,确实大开眼界。
第一周没派什么重活,主要是熟悉项目、熟悉流程、把环境搭起来:把 ZW3D 的源码拉下来,编译,能跑起来。该说不说,这个源码拉取、编译、运行是真的慢,代码体量也是真的大,差不多 86GB。而 ZW3D 本身是一套集成了 CAD(计算机辅助设计)、CAE(计算机辅助工程)、CAM(计算机辅助制造)、PDM(产品数据管理)的商业工业软件,整个代码库 1,591 万行 C++、35,316 个源文件、326 个构建模块、376 个架构模块。后来做静态分析时还接触到一个概念叫翻译单元(TU)——人话讲就是"每一个被单独拿去编译的 .cpp 文件连同它包含的头文件",ZW3D 全量有 25,498 个。只有真的见过这种体量,才知道"大工程"三个字的分量。
顺便留一条:这周还留了两条备注。Todo 是"等方案拍板后,对层级图的前端展示、yaml 的压缩与拍平做针对性优化";Think 是"项目里存在不少 Python 代码,用的是系统级环境,是否可以替换成 uv 并使用虚拟环境"。
2. 模块依赖可视化看板(约 45% 投入)
这是前两个多月的主线活。看板是接手前面实习生留下的框架做的:全局变量看板、矩阵页、趋势页他们已经做好了,模块依赖图这块基本是空的,只有一个 API 路由雏形,我来主导完成模块依赖图和矩阵视图的前后端。
第一步是拆 yaml。 ZW3D 的模块分层结构记录在一个叫 Zw3dArch.yaml 的配置文件里,分得比较粗。我先把它拆得更细,方便后续按需读取;后来胡老师给出了新格式要求 —— 给分层结构加上**领域(domain)**这一维度,我照着更新了 yaml,也同步改了对应的 Python(Flask)解析代码。数据格式一变,解析代码就得跟着变,这是我第一次体会到"配置即契约"。
然后是前端层级图。 我做了 chunk 的展开与折叠、快速隐藏层级、搜索框,还有跨层级 chunk 的跨层联动效果 —— 这个我改得最多,中间改过很多版都被说"不是想要的感觉",来回拉扯了好多轮才终于对上大家心里那个"感觉"。更难的是让这几块功能"认识彼此":已经隐藏的层级不能被搜索框搜到,跨层联动遇到隐藏层级就不触发,还要处理穿模问题。单独做哪个功能都不难,难的是让它们互相让路。另外我还写了一个自适应布局算法,能适配任何场景和屏幕大小,做出来和胡老师画的设计图简直一模一样 😎。
再然后是一个全新的模块依赖图页面。 拿到原型图(设计稿)之后,要实现节点之间的上下游依赖连线,并提供接口给其他系统调用。后端 API 都实现并沉淀出接口接入文档,还做了链接与筛选器的双向同步 —— 两边状态互相跟随,改一边另一边跟着变。后续又加了按业务领域(domains)列筛选节点、无限画布的图例关联更新、箭头指向优化,导出 svg/jpg 时带上标题、导出时间和图例,最后还修了"仅依赖节点"按钮的游离节点问题、加了自适应按钮。
这里有一个技术取舍值得记一下:模块依赖图本来可以用 Graphviz 自动画,最后改成了手写 SVG。原因有三个:这张图需要固定的架构分层布局;SVG 就是 DOM,在网页上直接绑交互事件天然方便;顺带避开了服务器部署 Graphviz 和中文字体兼容的问题。
到 8 月底阶段性收尾,统计下来是 8 个工作日(8/14–8/25)、17 次提交、13 个文件,累计新增 3,000 多行、净增约 1,200 行;另外交付了 170 行 API 接入文档,清理了约 700 行前人遗留的废弃实验文件。
3. 接手别人的扫描工具(约 10% 投入)
因为入职时正好有 2 个实习期满的实习生离职,我接手了他们的扫描工具。主要是头文件扫描工具:找出 C++ 代码里没被真正用到的头文件和多余的宏定义,然后安全清理掉。头文件之间互相包含,删错了直接编译不过,所以流程必须谨慎:静态扫描出候选(Clang-Tidy misc-include-cleaner)→ MSBuild 增量编译逐项验证 → 确认删除,失败自动回滚。整套流程覆盖 2.8 万+ 个源文件、72,574 条包含关系,实打实识别并移除了不少冗余头文件。
另外和另一位实习生一起共同维护基于 LLVM/Clang Tooling 的全局变量扫描工具 clang-global-variables-query(这个工具不是我写的,是团队 5-6 个人迭代了一年演进出来的,我做的是使用和迭代维护):针对真实误报/漏报样例调整匹配与过滤规则,工具正确性 100% 已经团队指定样例证实。
4. 从看板转战 Clang 静态分析(约 45% 投入,也是重头戏)
9 月初,叶博士跟我说有一个挑战性的任务需要我支援一下总部,于是工作重心转到了 Clang 静态分析规则上。
先是人工过告警。 一共有 1,306 条解引用候选告警,需要逐条人工处理,判断它到底是真的问题、误报、存疑还是其他问题;如果是真问题,还要对 ZW3D 源码做改动 —— 其实改动很简单,就是做边界判断、提前判空。这里说的"解引用"就是通过指针去访问它指向的对象(*p、p->x 这种),而这条规则盯的是 ZW3D 里的 ZwRef 无效引用检查,也就是智能指针的悬空引用问题。工具只能先把所有可能出问题的点扫出来,静态分析结果受宏、条件编译、传递包含、构建配置影响会产生误报,不能直接当结论用,所以才需要人一条条过。从 64/1306 推到 501/1306,真是非常费事费力还费眼睛 😅。过程中我还沉淀了一份避坑文档到公司的 ZWiki 上。
然后是 ZwRef 规则集编写(接手团队半成品后完成)。 ZwRef 是 ZW3D 团队自研的强引用智能指针,用错会访问到已失效的对象。这个检查器在我接手前是半成品,我基于 Clang StaticAnalyzer 的符号执行 / ProgramState / 约束求解,为它建立了路径敏感模型,累计约 3,100 行检查代码,挂到 clang-tidy 上统一调度。在全部 25,498 个翻译单元上全量扫描,初筛出 323 条候选告警,误报率压到 23.2%(团队目标是 40% 以内)。其中最关键的一刀:修复了 dynamic_ref_cast(把 ZwRef 转成子类引用的写法)在无法证明安全时被按"未知"处理的建模缺陷,单次就消除了 594 个纯 unknown 误报。
得诚实交代一句:ZwRef 检查器不是我一个人从零写出来的,是接手团队的半成品继续完善才达标的。不过能在别人的半成品上把它推到达标、还顺手改了产品源码,这种"接力"的感觉也挺好的。
更重要的是,我还直接改了 ZW3D 的商业源码。 基于检查器定位到的失效引用风险点,在几十个源码文件、上百个调用点位给 ZwRef 补充了判空与兜底判断,把静态分析的结论直接落到了产品代码修复上。改的是悟空 2027 的 C++ 本体,不是改 checker。当然这批改动最后没有合进主干,还停在本地,这是我走之前留下的一个"半成品尾巴"。
最后是迭代器/容器误用检查器(从零开发)。 这是我自己从零写的检查器,针对 ZW3D 里两类真实发生过的崩溃写法:对空序列容器调用 front() / back(),以及 find() 后没判断 != end() 就直接 erase()。做法上先用轻量的语法规则实现(AST 匹配 + 沿父链找判空守卫),之后升级为路径敏感的检查器 —— 把容器状态建模成空、非空、未知三种,状态跨调用、跨函数保持。
这个检查器一共迭代了 19 次,误报率从最初的 100% 降到最终 38.27%(< 40% 达标),50 处已确认真实缺陷全程稳定检出、零回归,告警位点从 1,121 收敛到 687,定向抑制了 134 个证据充分的误报点位。中间修掉了三个根因级问题 —— 注意,不是压阈值、也不是堆特例,而是修分析器本身的建模错误:
- 早期在误报点直接抑制告警会"污染"分析路径,改成先生成告警、报告期再过滤后,位点从 1,121 收敛到 694;
size() != 1 + 符号这类守卫存在无符号数回绕语义(无符号数溢出会绕回成极大值),在分支条件上证明快照非负可排除误解,位点到 691;- 花括号
std::initializer_list构造建模缺失,识别该构造并统计元素数后,位点到 687。
这套**“名单式抑制”**(用 SuppressionFile 在出报告时过滤已确认的误报,不影响分析过程本身)加上逐位点审计,是我这么多轮迭代下最花心思的一个设计:抑制必须发生在报告层,不能发生在探索层,否则分析器会以为那条路径没问题,可能探索出根本不存在的状态。听起来是小事,但它直接决定了这个工具可不可信。
顺便记录一个插曲:9 月中旬公司搞中秋活动,零食、饮料、猜灯谜、投壶、抽奖全上了,我抽到了 100 元整 😎。走之前还收到了中秋礼品 —— 4 个月饼、2 个杯子、2 个户外折叠椅,好家伙,合着是一套户外露营装备。
5. 中望的日常:自由、轻松、可以大胆创新
听其他实习生说,中望是 2026.07 才开始拥抱 AI 赋能,也就是刚用上 AI 几天后我就入职了。他们专门弄了一个叫硅基加拉帕戈斯的内部平台,有 token 使用排行榜、可以许愿求助,每个人(包括实习生)都能编辑,很自由。中望的定制化也很强:深信服定制的瘦终端式源码机办公、定制的 CC-Switch,还有特别像 opencode 二次开发的 Firmior AI。ZWiki 上的内部资料非常齐全,规则流程什么的非常规范。
中望给人的感觉是:自由、轻松、可以大胆创新。每周四上午固定的组会是我最怕也最受益的一段;每周还有球赛,同事过生日会有前台小姐姐递来的蛋糕水果,还有集日常与工作于一体的"望事通"—— 健身百日打卡、二手攻略、销冠记录、美食推荐、视频课程,什么都有。
还有一件事值得一提:8 月 10 日是我在中望唯一一次请假。那天台风"白海豚"正面扑上海,我住在江边,内陆人第一次见台风 —— 伞撑不开,浑身是湿,地铁关闭运营起大早跑到地铁口,又变成落汤鸡走回来 🤡。也正因为这样,那两周恰好赶上"挑战性任务"的启动,有点因祸得福的味道。
3. 这三个月遇到的那些人
叶博士:部门领导,带我认识每一位同事,也是给我派"挑战性任务"、让我从看板转战静态分析的人。没有他的信任,我三个月都摸不到 Clang 静态分析的门。
胡老师:负责拍板 yaml 新格式、给设计图的人。层级图做出来"和胡老师画的一模一样",是我那周最开心的事之一。
guoxiaotao:看板框架的作者,我接手的是他的半成品 —— 全局变量看板、矩阵页、趋势页都已成型,模块依赖图这块基本是空的。接手别人的活儿继续做完,本身就是一种传承。
一起维护全局变量扫描工具的另一名实习生:我们主要围绕真实的误报/漏报样例共同排查,先用人工确认结果做对照,区分误报与漏报,再定位到匹配或过滤规则,修改后重复扫描并回归旧样例。改完我还负责把扫描数据接到看板上,从展示端反查结果对不对,形成双向核对。
两位实习期满离职的前辈:入职第二周他们就走了,我接过了他们的扫描工具。走之前 guoxiaotao 那句"这块就交给你了"的分量,隔了很久还记得。
HR 小姐姐:入职第一天带着我走遍公司各个角落,介绍每一个部门。
一群爱折腾的同事:球赛、生日蛋糕水果、望事通里的各种分享,还有一起在硅基加拉帕戈斯上许愿求助的同仁。
4. 回头看
三个月的实习,跟上一段比最大的不同是:这次不是被各种环境问题追着跑,而是真的往深处扎了一根。
第一,见过大代码库之后,对"工程"有了敬畏。 1,591 万行 C++、86GB 源码、2.5 万个翻译单元 —— 在这种体量面前,任何"我懂了"都是暂时的。你改的每一行代码,都可能被几十个模块依赖着。我改 ZwRef 判空的时候,每补一个 if,都得想清楚会不会改变原有的语义。
第二,静态分析的可信度是修出来的,不是声明出来的。 一个检查器从 100% 误报到 38.27%,靠的不是调阈值,而是把建模错误一个个修掉:抑制污染路径、无符号回绕、initializer_list 构造缺失。真正让工具可用的,是"名单式抑制"这样朴素但正确的设计 —— 该修的地方修,该隔离的地方隔离。
第三,人工逐条看 1,306 条告警,是最笨也最必要的功夫。 没有这一遍费眼睛的人工分类,就没有后面规则集的优化方向。工具只能扫出"可能",把"可能"变成"确定",靠的是人。这一点和上一段的体会完全一致:工具再好,也得有人愿意一条条看完。
第四,也是我给自己的提醒:接手 ≠ 从零开发,完成 ≠ 冒领。 ZwRef 是半成品接力,看板是框架上加子系统,扫描工具是使用与维护,头文件清理是"扫描 + 编译验证 + 回滚"的安全流程 —— 每一件我都得说清楚我到底做了什么。这一点在简历和面试里都不能含糊,糊掉的不是数字,是可信度。
第五,团队文化真的很重要。 允许实习生编辑内部 AI 平台、允许大胆创新、节假日的仪式感拉满,还愿意把最难啃的静态分析任务交给一个实习生。在这样的环境里干活,幸福感是实打实的。
5. 几个我记得的数字
- 86 GB:ZW3D 源码仓库的体积,光拉取编译就够喝一壶
- 1,591 万行 / 35,316 文件 / 326 构建模块 / 376 架构模块 / 25,498 翻译单元:ZW3D 的代码体量
- 8 个工作日 / 17 次提交 / 13 个文件 / 新增 3,000+ 行 / 净增约 1,200 行:模块依赖看板阶段性收尾的统计
- 170 行:API 接入文档;700 行:清理的前人遗留废弃代码
- 45% / 45% / 10%:看板、规则集、扫描工具链的投入占比
- 1,306 条:解引用候选告警,人工一条条过(从 64/1306 推到 501/1306)
- 3,100 行 / 323 条 / 594 个 / 23.2%:ZwRef 规则集的检查代码量、告警数、单次修复消除的误报数、最终误报率(目标 < 40%)
- 19 次迭代 / 100% → 38.27%:迭代器检查器的迭代次数与误报率收敛(目标 < 40%,达标)
- 1,121 → 694 → 691 → 687:迭代器检查器告警位点的收敛过程
- 134 个 / 50 处 / 0 回归:定向抑制的误报点位、真实缺陷稳定检出数、修复过程零回归
- 100%:全局变量扫描工具的正确性(团队指定样例已证实)
6. 这段实习碰过的东西
不是技术栈清单,只是实习期间接触过的东西。有些用得多、算是上手了;有些只是当时用一下,现在忘得差不多了 🤣,列在这里权当个记录。
- C++20:写检查器的主要语言
- LLVM / Clang Tooling、Clang StaticAnalyzer、clang-tidy、AST Matcher:静态分析主战场
- 符号执行 / ProgramState / 约束求解 / MemRegion 三态建模 / 路径敏感分析:检查器的理论基础
- CMake / MSBuild:构建与增量编译验证
- Python / Flask / SQLite:看板后端
- JavaScript / 原生 SVG / ECharts / Panzoom.js:看板前端(手写 SVG 替代 Graphviz)
- Graphviz:试过又放弃的自动画图方案
- ZWiki:公司内部知识库,我也往上面贡献过避坑文档
- 硅基加拉帕戈斯 / 望事通 / CC-Switch / Firmior AI / 瘦终端源码机:中望的定制化数字生活
就这样,我的中望实习在 2026.09.28 画上了句号。离开那天,我提交了迭代器检查器的最终版,也修好了看板复发的一个小 bug —— 有始有终,挺好的。感谢中望,感谢软件框架小组的每一位同事。江湖路远,后会有期 👋















